rubberduck-vba / Rubberduck

Every programmer needs a rubberduck. COM add-in for the VBA & VB6 IDE (VBE).
https://rubberduckvba.com
GNU General Public License v3.0
1.92k stars 301 forks source link

Format requires a reference #418

Closed eteichm closed 9 years ago

eteichm commented 9 years ago

Hi

I'm using Rubberduck v1.22.
When executed by an end user, the below code requires a missing Rubberduck reference: Msgbox "File processed in " & Format(now - begin, "hh:mm:ss") Unchecking the Rubberduck reference solves the issue.

Does Rubberduck includes a Format function? If so, how should I call the vba Format function?
Have I missed something?

Thanks for this great tool! Eric

rubberduck203 commented 9 years ago

I don' t think we've exposed any such method in our API, but I'll look into it to make sure I'm not missing something.

In the meantime, you can explicitly reference the standard VBA library to resolve the namespace issue.

`VBA.Format(now - begin, "hh:mm:ss")`

(Untested, let me know if that works.)

retailcoder commented 9 years ago

Indeed, there is no Format method in the RD type library.

Adding a test module to your VBA project adds a reference to Rubberduck.tlb and an early-bound instance of the AssertClass, so that you can author your unit tests with IntelliSense on the Assert object.

When you distribute your project to end users, the unit-testing code no longer needs the early-bound reference, and if end users don't have the .tlb in their machines your code will produce weird compile errors as you're experiencing.

@ckuhn203 qualifying the Format function will only possibly move the problem elsewhere, the code will refuse to compile as long as there's an early-bound AssertClass instance in the project.

The solution is to remove the project's reference to Rubberduck.tlb and late-bind the AssertClass instance in the test modules, like this:

 Private Assert As Object

The late-binding needs to be done in the ModuleInitialize procedure, like this:

 '@ModuleInitialize
 Public Sub ModuleInitialize()
     Set Assert = CreateObject("Rubberduck.AssertClass")
 End Sub

And then the ModuleCleanup procedure can destroy the instance:

 '@ModuleCleanup
 Public Sub ModuleCleanup()
     Set Assert = Nothing
 End Sub

(the @ annotations should be optional if you're using these exact method names)

This way the unit tests can still run on a machine that has RD installed, and the VBA project will compile on a machine that doesn't have it.

Next release the test module template will make it easier to switch to late-binding:

Option Explicit
Option Private Module

'@TestModule
Private Assert As New Rubberduck.AssertClass
'Private Assert As Object 'remove reference to Rubberduck and uncomment this line for late binding

'@ModuleInitialize
Public Sub ModuleInitialize()
    'this method runs once per module.
    'Set Assert = CreateObject("Rubberduck.AssertClass") 'uncomment this line for late binding
End Sub

'@ModuleCleanup
Public Sub ModuleCleanup()
    'this method runs once per module.
    'Set Assert = Nothing 'uncomment this line for late binding
End Sub

'@TestInitialize
Public Sub TestInitialize()
    'this method runs before every test in the module.
End Sub

'@TestCleanup
Public Sub TestCleanup()
    'this method runs afer every test in the module.
End Sub
rubberduck203 commented 9 years ago

Another option is to export and remove your test modules from the project prior to release.

retailcoder commented 9 years ago

@ckuhn203 not really. You'd still have to remove the RD reference, and exporting/re-importing the test modules would be a pain in the neck. We've made sure AssertClass could be late-bound specifically for this.

retailcoder commented 9 years ago

I'm closing this issue; #291 is closely related to this.

eteichm commented 9 years ago

@retailcoder Thanks for the detailed answer. I'll test it.