[??] How to pass a variable from main.rb to a boxtool
-
Hi !
I have 2 files:
- main.rb, and
- rs_boxtool.rb
I would like to pass a variable from main.rb to rs_boxtool.rb, setting the size of the box. The idea is to use @boxheight as a variable. Is that possible?
main.rb:
require ('as_plugins/as_rubyeditor/snippets/rs_boxtool.rb') @boxheight = 100 # It's a variable inside the tool, but it dont work! boxtool = BOX_tool.new Sketchup.active_model.select_tool boxtool
rs_boxtool.rb:
class BOX_tool def initialize @mod = Sketchup.active_model @ent = @mod.entities @view = Sketchup.active_model.active_view @state = 0 inches = 1 @mm = inches.to_mm #@boxheight = 1800/@mm # --> This sould be accessed from the rs_boxcall.rb file #---box def.start--- @pts = [] @pts[0] = [0,0,0] @pts[1] = [0,0,@boxheight] @pts[2] = [0,@boxheight,@boxheight] @pts[3] = [0,@boxheight,0] #---box def.slut--- end def activate end def onMouseMove(flags, x, y, view) if (@state == 0) # Create box_group ip = Sketchup;;InputPoint.new ip.pick view, x,y ip = ip.position @yv_group =Sketchup.active_model.entities.add_group @yv_face1 = @yv_group.entities.add_face (@pts[0], @pts[1], @pts[2], @pts[3]) # basis side point = Geom;;Point3d.new ip new_transform = Geom;;Transformation.new point @yv_group.transformation = new_transform @state = 1 end if (@state == 1) # box follow mousemove ip = Sketchup;;InputPoint.new ip.pick view, x,y ip = ip.position Sketchup.status_text = "@state = 1 ; Inputpoint; ", ip point = Geom;;Point3d.new ip new_transform = Geom;;Transformation.new (point) @yv_group.transformation = new_transform end if (@state == 2) # onLMouseButton place boxgroup in choosen position ip = Sketchup;;InputPoint.new ip.pick view, x,y ip = ip.position ip = ip.x-0.1/@mm, ip.y , ip.z Sketchup.status_text = "@state = 2 ; Inputpoint; ", ip point = Geom;;Point3d.new ip new_transform = Geom;;Transformation.new (point) @yv_group.transformation = new_transform @ip1 = ip @state = 3 end def onLButtonDown(flags, x, y, view) if (@state == 3) self.reset end if (@state == 1) @state = 2 end end # onLButtonDown end def reset @state = 0 end end # class BOX_tool #boxtool = BOX_tool.new #Sketchup.active_model.select_tool boxtool
Thanks in advance.
-Rasmus
-
@unknownuser said:
@boxheight = 100 # It's a variable inside the tool, but it dont work!
In main.rb, it's an (undefined) variable outside the tool.
In rs_boxtool.rb, it's an instance variable that does not exist as long as you haven't created an instance of the class (that's what you do later withboxtool = BOX_tool.new
)One possibility is to make the instance variable available from outside via attr_accessor [the link is for Module but it works for class instances too (?)]. You can then change the instance variable (under the condition that you first create the instance):
require ('as_plugins/as_rubyeditor/snippets/rs_boxtool.rb') boxtool = BOX_tool.new boxtool.boxheight = 100 Sketchup.active_model.select_tool boxtool
class BOX_tool attr_accessor ;boxheight # ... end
attribute_accessor
basically creates a new method (with the same name like the variable) to change the variable's value. -
Typically...
Common named Modules share @variables across sessions, until overwritten.
Common named Classes share @@variables across sessions, AND @variables per class-instance, until overwritten. -
@rvs1977 said:
I would like to pass a variable from "main.rb" to "rs_boxtool.rb", ....
In Ruby.. the file does not create a namespace context (like it does in Python.)
In other words... the beginning and end of a file, means nothing to Ruby. It is not the beginning and ending of code, in Ruby's eyes, it's just a bunch of lines of code.
You must explicitly declare your own namespace (using
module
,) in BOTH files, so that the code from each file, runs within the same context. In that way.. the files can access variables defined in either file.If you do not wrap your code within an author module (say
module RVS
as an example,) then the code will run within theTOPLEVEL_BINDING
which isclass Object
.
The problem is that EVERYTHING in Ruby is an object, and therefor a subclass ofObject
, and your variables, methods, etc. in the unwrapped code will propagate into EVERYONE's classes and modules.. ie ALL other objects.See these threads where other persons asked almost the same question:
how toget a Settings Menu to communicate with a Main Menu?
and:
Program format -
First of all, thank you for all the answers. Its really helpful.
Even though its a little abstract to me right now, I know which direction to go. I belive the answer is using an author module. I will try to find out the difference between module and class
-
@rvs1977 said:
I will try to find out the difference between module and class
The difference is simple:
class
Class
is a subclass of classModule
.Generally... when you need ONE copy of some code, you use a
Module
. (Also when you need to create a namespace, or subnamespaces, to separate the execution context of some code, from all other code,... be it your code or the code from the rest of the world.)When you need instances (multiple copies,) of some code, you use a
Class
, and create instances using the class' constructor methodnew()
. (There are situations when you must use aClass
, but only ONE instance is allowed. This is called a singleton class.)Good rules to follow for classes:
1) Only Ruby base classes should be defined as a global class, at the toplevel.
2) Author classes that will be used by more than one of your plugins, should be defined, just inside your author toplevel namespace (module.)
3) Each one of your plugins should be defined within a submodule (at some nesting level that YOU choose,) inside your author toplevel namespace (module.)
4) An author class, that is specific to a certain plugin, should be defined within that plugin's submodule.
Just as you would organize your directory hierarchy, where your code files reside... you can organize your namespace hierarchy in the same manner.
I talk about it in this tutorial:
[ Code ] SketchupExtension and rbs rubies -
BTW.. did you install the full Ruby version ??
Ruby (v1.8.6-p287) Windows One-Click InstallerWhen you do.. you will have the full CHM file for
"Programming Ruby - The Pragmatic Programmer's Guide, 1st Ed."
in your "C:/Ruby186/doc" directory. -
I get the point using namespaces, so I decided to find out how module works by making the simpelts possible example... and it dont work
Again with 2 files:
- rs_main.rb, and
- rs_moduletest.rb
From rs_main.rb I call a method defined inside rs_moduletest.rb. The method then should write in a messagebox "Hello World".
rs_main.rb:
module RVS; end module RVS;;MyPlugin # declare module vars and constants first @@myHelloVar = 'Hello World' # require other parts of this plugin; require('as_plugins/as_rubyeditor/snippets/rs_moduletest.rb') # main plugin script, menu items, etc. MyPlugin.test() # Calling the test-method from rs_moduletest.rb end #module RVS;;MyPlugin
rs_moduletest.rb
module RVS;;MyPlugin public def self.test () UI.messagebox @@myHelloVar end end #module RVS;;MyPlugin
how should this be written to work?
-
@dan rathbun said:
BTW.. did you install the full Ruby version ??
Ruby (v1.8.6-p287) Windows One-Click InstallerWhen you do.. you will have the full CHM file for
"Programming Ruby - The Pragmatic Programmer's Guide, 1st Ed."
in your "C:/Ruby186/doc" directory.No I havn't. But I will
-
"rs_moduletest.rb":
remove the space between the method name and the opening "(" for the argument list. Never put spaces between them, either when defining them, or calling a method. An error can occur that gives very weird messages in Ruby 1.8.6."rs_main.rb":
What you are doing wrong is trying to call a method from within namespaceRVS::MyPlugin
that is first looking within that namespace for a constant identifying an object namedMyPlugin
, but there not one.. so second, Ruby goes up to the top level and looks there again for a constant identifying an object namedMyPlugin
, but again does not find one, so it raises aNameError
exception.Either:
1) use the
self
keyword, which within a module, returns a reference to the module itself.
so line 12, can be:
self.test()
or 2) define your plugin methods within a proxy class block:
"rs_moduletest.rb":module RVS;;MyPlugin class << self public def test() UI.messagebox( @@myHelloVar ) end end # proxy class end #module RVS;;MyPlugin
Notice how in this case you do not define the method prefixed with "
self.
" ??
then in "rs_main.rb", you simply call the method by name only, as you would in a class instance:
test()
You may also use the global methodprivate
(instead ofpublic
,) if you wished your module'stest
method to be called only (easily,) from within it's module.Also... the method
test()
is a very important global method for testing files and directories, and it is inherited by your modules.
But since, they are YOUR modules, you are allowed to override inherited methods. If you still wanted access to the global method, you would need to qualify it's call as:
Kernel.test(?d,"C:/Ruby186")
which tests if "C:/Ruby186" exists and is a directory. -
Finally it works!!...
BUT I had to move the rs_main.rb from the "\Plugins\as_plugins\as_rubyeditor\snippets"-folder to the "\Plugins"-folder, and then restart SU. At start up it showed the Alertbox "Helle World".
BUT It won't work if I use the playbutton in AS-code editor. It seems like, when using modules, it has to be loaded into SU at startup.
I wonder if there is a way to come around this?
EDITED 1: It can be run directly from the snippet folder with ruby console (then SU requires no restart):
load 'c:\path to the program\Google SketchUp 7\Plugins\as_plugins\as_rubyeditor\snippets\rs_main.rb'
EDITED 2: in rs_main.rb
require
is changed toload
. Then it updates the variables when its changed.So far so good! Thank you...
Advertisement