Closed SmileyFtW closed 4 years ago
I wonder whether this could be co-opted in the "Encapsulate Field" refactoring we already have...
somewhat related: #4805, #875
I don't really know what that means (co-opted in the "Encapsulate Field") ... but then I have only begun my RD journey. If you can point me in that direction I'll happily explore it.
@Vogel612 I think it should be a separate "Unwrap Private Type" refactoring, or something like it.
@SmileyFtW the operation is somewhat similar to that of the existing "Encapsulate Field" refactoring; Vogel is suggesting to enhance the existing refactoring with the ability to "unwrap" (I totally just came up with that) a private type into a bunch of properties.
I am having a blast using RD and applying the principles I've found on the WordPress site. Thanks for everything y'all do.
Since I was "wishing", I thought I would add another item to this request. When an item in the Type declaration is an Object also include the Class Init and Terminate procedures with an instantiation of the object(s) and setting them to Nothing.
@SmileyFtW caveat: can only work for classes that are creatable.
Set this.Thing = New Object 'invalid
That would be fine, i would think, since doing something like that as part of the Type declaration would need special attention by the coder anyhow. But all valid declarations would still be a nice convenience.
I agree, however I'd rather avoid generating code we know is invalid in the first place :)
@SmileyFtW : I with you on this one.
@Vogel612 & @retailcoder : (as a reference) in mzTool there is a properties helper. We declare property name, type and private property name, pick GET/SET/LET'ers.
It works nice for a single property per step. It produces code like this.
Private _fooBar As String '_ is default prefix
Public Property Get FooBar() As String
FooBar = this.FooBar
End Property
Public Property Let FooBar(ByVal NewValue As String)
this.FooBar = NewValue
End Property
This will be a very very helpful addition. :)
I am in the process of writing VBA to do this for me and my limited use cases. It'll end up being an add in. It will look for all open workbooks that have at least one list object (table) and present the workbooks as candidates (optionally Browse... to open a workbook). Selecting a candidate will list all worksheets that have tables. User will select the tables to be used. Models and Proxies will be created along with Presenters and UserForms with Apply and Cancel buttons. IData and IDialog interfaces implemented in the appropriate related modules.
I have completed the initial cut at this and created a repository for it on GitHub (I hope that is the proper place for something like this: https://github.com/SmileyFtW/CreateCodeWithCode).
There are 2 files in the zip file. One is the file that does the work and the other ("TestWorkbook") is a proper file for doing the code creation. A "proper file" is one that has at least one worksheet with one table and has not been processed previously by the code creation file. I did not do any Unit Testing set up and would greatly appreciate any input on what would make sense to do unit testing on in the code creation file as well as other observations, comments, etc.
Open both files. With the code creator as the active file, a menu in the ribbon has a button that starts the process. I trust it is self explanatory what to do once launched.
The end goal is to turn this into an add-in, but for now it is just a macro-enabled file.
DId it a little differently here: https://github.com/SmileyFtW/GeneratePropertyGettersSettersFromBackingFieldsInXLVBA
@SmileyFtW
I don't really know what that means (co-opted in the "Encapsulate Field") ... but then I have only begun my RD journey. If you can point me in that direction I'll happily explore it.
Maybe you already have investigated the EncapsulateField
refactoring, but just in case you have yet to:
Based on your initial example, you can get what you are after if you let RD/EncapsulateField create the Private Type based on individual fields.
Public Property1 As String
Public Property2 As Long
Public MyCollection As Collection
Public MyObject As MyObjectModel
Property1
and use the Rubberduck context menu to navigate: Rubberduck => Refactoring => Encapsulate FieldUsing the EncapsulateField dialog:
checkbox
(The Preview shows you what will be generated)The generated/refactored code:
Private Type TModule1
Property1 As String
Property2 As Long
MyCollection As Collection
MyObject As MyObjectModel
End Type
Private this As TModule1
Public Property Get Property1() As String
Property1 = this.Property1
End Property
Public Property Let Property1(ByVal value As String)
this.Property1 = value
End Property
Public Property Get Property2() As Long
Property2 = this.Property2
End Property
Public Property Let Property2(ByVal value As Long)
this.Property2 = value
End Property
Public Property Get MyCollection() As Collection
Set MyCollection = this.MyCollection
End Property
Public Property Set MyCollection(ByVal value As Collection)
Set this.MyCollection = value
End Property
Public Property Get MyObject() As MyObjectModel
Set MyObject = this.MyObject
End Property
Public Property Set MyObject(ByVal value As MyObjectModel)
Set this.MyObject = value
End Property
Use RenameRefactoring to adjust any identifiers.
Wow.. Guess I need to look into it. I've jut gotten into the habit of starting with Private Type
and putting in the backing fields. Does the Refactoring have the ability to start with the Private Type
?
Yes it does.
Using your example: Select just the this
identifier from Private this As TModel
. Do not check the 'Wrap Fields in Private Type' checkbox (or you end up wrapping this
in a new UDT)
Now that sounds precisely like what I was after. sigh.... but then it was a good learning experience for me to write what I did
That is wonderful! RD keeps on surprising me with everything it does.
@BZngr FYI the Encapsulate Field refactoring is now a "highlight" on the website's home page carousel; every time the home page is served, 5 features are picked at random, and Encapsulate Field is representing the Refactorings feature.
I find myself starting a model (or proxy) like this a lot:
Then writing all the Get/Let procedures. It sure would be nice to write the Type and this declarations and then hit a button to have the Get/Let procedures be automatically generated.