Ruby namespace?
-
@jessejames said:
Have you even coded Ruby before? Do you understand what you are saying. If you mean to say that i am no Ruby Guru, then yes, you are right. But i know enough about languages to call Ruby out on some of it's asinine behaviors. My argument about the end statement is as follows...
No need to get over-sensitive about this. Apparently, I've coded Ruby enough to know how it handles namespaces. Your original question implied you hadn't researched enough to understand it yourself. It would be pointless to get into debates on Ruby vs. Python vs. ... many of these issues come down to personal preference. Now days, it seems there are about as many programming languages as there are programmers. Your comments about readability when using "(...)" could be just as well applied to the "end" statement. BTW, I personally dislike Ruby's optional use of paren's, but I also like the readability of an end statement (not everyone uses good indentation practices, etc).
Ruby is the SU programming API, so until that changes, it makes more sense to learn what Ruby can do versus complaining about how bad it is compared to some other language.
-
I see what you are saying, we can't just change something as important as the API because some person say's "hey this language is better or that language is better".
But what is the target audience for the SU Ruby API(or any API for that matter?) -- It is SU modelers, NOT professional programmers(although i am sure a few exist here). They need a language that is easy to learn, powerful, widely known, has a future, and most importantly has tons of good documentation. I think anybody (that actually knows Python and Ruby) will hands down agree that Python meets all these standards "ESPECIALLY" documentation. There are so many good tuts across the net that you would have to be blind not to find one. Python is easier to learn and will increase productivity. I am sorry but not only are the API docs lacking ,this poor amount of documentation extends into the world of Ruby. I have yet to find a GOOD, complete Ruby tutorial for non-programmers.
There exists now in the world of high-level languages only two big boys -- Python and Ruby. As far as i am concerned Python is the better of the two if learnability, and readability are your main concerns. I think Python is simplistic programming elegance! As Guido puts it. "Python is less footprint on the brain". I believe if you are an experienced Perl coder you will love Ruby, else you will find it quite confusing.
One of the really great things about Python is the support for true procedural style coding. Ruby's scoping rules won't allow true procedural code without using instance vars. A new programming student quest will be much less painless if they can start with a procedural style and ease into OOP (IMO). I love OOP, but trying to grasp OOP and general programming semantics at the same time can be quite painful. Not to mention that not every problem warrants the use of OOP's machinery, a lot of times OOP can be complete overkill.
Listen, if Ruby where the better language i would happily jump on the Ruby bandwagon and preach to the masses, but IMHO, Python is truly a better choice for any API.
I am not here to just run my mouth, i quite intend to back it up. I would like to have a "Pepsi Challenge" between Python and Ruby using non-programmers. I believe if given the option most (80% or more) would gravitate to Python. Anybody want to accept this challenge?
-
@david. said:
[snip] ...Your comments about readability when using "(...)" could be just as well applied to the "end" statement. BTW, I personally dislike Ruby's optional use of paren's, but I also like the readability of an end statement (not everyone uses good indentation practices, etc).
[snip]Python forces indentation, so you would never have to worry about poorly indented code. Now your reasoning for keeping the end statement falls completely apart.
ps: Don't let the Gun and wanted poster fool you, i am a very easy going person
-
@jessejames said:
ps: Don't let the Gun and wanted poster fool you, i am a very easy going person
are you easy going enough to have a look at SuPy and see why SU7.1 won't load the python bundle
http://www.cosc.canterbury.ac.nz/greg.ewing/SuPy/
I don't know anything about scripting, I but need to use this hypocycloid.txt py script in SU,
I can't get SuPy to work and don't know ruby or python to convert it...
or anyone else have any ideas
john
-
There's a lot to be said for Ruby. However, I do think that Python's suites (just indent, no "end" or "}" needed) are an elegant solution for blocking code.
-
Is there a way to get a reference to this anonymous namespace crated by load?
I'd like to do something like this:
anon_namespace = load ( "/path/to/command.rb", true ) menu.add_item(anon_namespace.text) { anon_namespace.command }
-
@jim said:
Is there a way to get a reference to this anonymous namespace created by load?
I'd like to do something like this:
anon_namespace = load("/path/to/command.rb",true) > menu.add_item(anon_namespace.text) { anon_namespace.command } >
First of all load returns true/false for success or raises exceptions (such as LoadError, or SyntaxError from eval,) so you can't get it in that way.
It can be got... but must be got from INSIDE the object.
Also.. it's a temporary namespace.
It needs to be used ONLY for UnWrapped linear scripts, that don't need any persistant objects (such as the cmd or text attribute vars in your 'wishcode' above.)So the UI::Command class instance object(s) need to be outside the temporary namespace, because they must persist for the session, in order for the menus to work; and their callblocks would be:
{ load('*somefile.rb*',true) }
Here's a couple of test files:
-
@dan rathbun said:
Here's a couple of test files:
If you run the test scripts from the console, ie:
load 'test/UnWrapped.rb',true
and
load 'test/NoName.rb',true
you'll see that the annonymous namespace is assigned an identifier such as:
#<Module:0x55EF32A4>
it's basically a temporary pointer.
Before you could do anything with it, the loaded script would be done parsing or loading or running and ruby will have set the pointer to nil.
You can try it after running either script (they will report what the identifier is,) type the name of the identifier at the console with .inspect if you wish. Example:
` #Module:0x55EF32A4.inspectnil`
_ -
@jim said:
@jessejames said:
I noticed when i do obj.methods, and obj.private_methods, there is a lot of pollution in there. Names that obviously don't belong to that obj.
I wouldn't call it pollution. You're seeing all the methods that the object has. Some of them are inherited, some are class methods, others are instance methods. I suspect what you expected to see were only the instance methods of a class.
This is VERY important! For understanding Ruby,... but more so.. how the Sketchup Ruby API (and standard Pure-Ruby extensions (such as 'sketchup.rb' [as the best example,]) can be incorrectly implemented.
Ruby scripts... (if you don't tell them specifically what namespace to run in,) will run in (the global constant namespace,) TOPLEVEL_BINDING. (A Binding class object, is 'sort-of' an execution directive to a namespace.)
(1) TOPLEVEL_BINDING is preset to Object (uppercase.)
(2) Everything in Ruby is an object (lowercase,) meaning it is either an Object class, or a subclass (at some level of descendancy,) of Object class. [You may think of the lowercase word 'class' as 'type' if you come from a language where 'type' is more understandable. But recent revisions to Ruby are attempting to remove the word 'type' in favor of 'class.' Keep in mind that there is in Ruby a class Class, which is subclass of class Module, which is subclass of class Object.]
(3) The Sketchup Ruby Console operates in TOPLEVEL_BINDING. (Open the console and type: self <ENTERkey> , what do you see?
(4) Any script loaded runs in TOPLEVEL_BINDING.
(5) This means that most objects defined in TOPLEVEL_BINDING are in fact then defined WITHIN class Object. So if you define a method (without wrapping it with a Class or Module namespace, it is defined as a method of class Object. (Take a look at the 'sketchup.rb' script in the Tools folder and note the names of the methods defined there.)
(6) As every object in Ruby is a subclass of Object, every object will inherit (in some way,) those objects defined within class Object, including methods, constants, etc. IF you have incorrectly defined them there.
(7) The methods within the 'sketchup.rb' script were intended (for the most part,) to extend developer's use of the classes Module and Class. BUT they were not wrapped within the proper namespace(s) in the script, and so get defined as methods of Object, and so become inherited by ALL classes, such as the Numeric classes, the Sketchup::Entity subclasses, the Geom::subclasses, etc. where they will NEVER be used.
Open a new model, draw something simple a cube, select a Sketchup::Face object. Switch to the console, type (all 1 command):
**Sketchup.active_model.selection[0].private_methods(true).sort.join("\n")**
Look at the list, you will see that the Face object has inherited as private methods (which you will never call from outside the object,) all those methods defined in 'sketchup.rb'!
What kind of drain of memory will this have when you get to a model that has tens of thousands of Entities it it?"How do you fix this?"
(a) ANSWER: 'sketchup.rb' MUST DIE! The methods within NEED to be moved (defined as an extension,) to the proper %(#BF0000)Module where they should have been added in the first place:to module Sketchup:
-
file_loaded* file_loaded?* require_allto module UI:
-
add_separator_to_menu* inputbox (really a patch that needs to be made part of UI.inputbox.)
(b) Edit any script you use, that does not wrap it's code in a module namespace, especially method definitions with a module wrapper. Don't use any rbs (scrambled ruby) that you cannot wrap. (Contact the author and ask they wrap their code.)
(c) If you can.. use the load method with the wrap parameter set true, for menu command scripts, etc. when editing many many plugins is not an option. (The wrap argument for load will wrap the script in an anonymous namespace, and protect the global namespace from corruption.)
(d) Ask the Google Sketchup Team to fix the Sketchup::load method to expose the wrap argument, so we can specify wrap=true for rbs scripts. For some unknown reason, they defeated, or just didn't pass the 2nd argument (wrap) on to the aliased standard load, when they overrode it to handle rbs decrypting.
_ -
-
@dan rathbun said:
(7) The methods within the 'sketchup.rb' script were intended (for the most part,) to extend developer's use of the classes Module and Class. BUT they were not wrapped within the proper namespace(s) in the script, and so get defined as methods of Object, and so become inherited by ALL classes, such as the Numeric classes, the Sketchup::Entity subclasses, the Geom::subclasses, etc. where they will NEVER be used.
Very informative post Dan! But i disagree that the problem boils down to a lowly script. This problem is inherent in the design of the Ruby language itself!
@dan rathbun said:
Open a new model, draw something simple a cube, select a Sketchup::Face object. Switch to the console, type (all 1 command):
**Sketchup.active_model.selection[0].private_methods(true).sort.join("\n")**
Look at the list, you will see that the Face object has inherited as private methods (which you will never call from outside the object,) all those methods defined in 'sketchup.rb'!
What kind of drain of memory will this have when you get to a model that has tens of thousands of Entities it it?Exactly! this is what most of the folks in this thread have missed! Ruby just blindly sucks in every method it can find! In Python we have a system of using single and double leading underscores to indicate private and public methods. It's not a forced convention but we all understand and use it like a forced convention.
But even more importantly Python objects have a dir "special method" that will return the appropriate list of methods when using the introspection function dir(obj). Python also (as i have mentioned time and time again) uses every file as "module" automatically so none of the name clashing occurs unless you import the module in a certain manner.
Advertisement