Problem with group.copy
-
I have a client who is getting a problem when we execute copy on a group.
the group is saved in $beam_group, and I had him type in:
$beam_group.copy
and Ruby returns 'nil' (Which means that the command $beam_group.copy did not return anything. - Usually it returns something like: #Sketchup::Group:0xf9c8d94)
Can anyone think of a time when group.copy has failed?
Can anyone thing of a time that you cannot copy a group?
(I just created the group myself previously in the Ruby)
I will ask him to type in:
$beam_group.entities
and
$beam_group.entities.length
That might give me a clue.
-
Is it making the copy BUT simply failing to return a suitable reference to it ?
Are you sure he's typing its reference correctly ?
What does he get if he simply types$beam_group
?
Incidentally, why use a global-variable [$
] which might clash with another tool? when you could always use@beam_group
or@@beam_group
within a method/class/module etc that is thereby 'contained' and not 'public' ??
You should get a valid copy of a group even if it is empty... i.e. whengroup.entities.length==0
- so a mystery ???
Obviously any completely empty groups within a start/commit block are auto-purged...The only other possibility is that he/you have some script that's loading that refines the method group.copy to return 'nil' rather than a reference to the new copy... to check for that you'd need to run a Baregrep [or similar] on the Plugins folder for 'def copy' or 'class Sketchup::Group', and see what is throw up...
-
Thanks for your thoughts TIG.
Inside our ruby we use just 'beam_group'. I added $beam_group = beam_group to the ruby to make it easier to debug the problem the client is having.
I asked him to type in just $beam_group and report the results, but he failed to do that.
Our ruby file does trace the value of beam_group just before the error occurs, ("beam_group: #Sketchup::Group:0xfa63fec"), so it is probably an actual group. If it something else, (except for a few things), then $beam_group.copy would return an error rather than nil.
It is difficult to determine whether it made a copy and failed to report it, since the client is in a different time continent and time zone.
You are right about empty groups, I just tried:
$beam_group.entities.clear! and
$beam_group.copyand if worked (returned a non nil value).
And, (of course ) The whole process works on my machine.
I will ask him to run all this in an empty model, so I can see what the beam group looked like before it tried to copy it and if anything did get copied. (The whole process stops after the error on the next line when I try to use the 'nil' copy.
This is all part of a ruby which creates parallel semi-transparent light beams to emulate a smokey light effect.
-
I'll wager that he is misunderstanding and typing
$beam_group
or$beam_groupcopy
... and then getting 'nil' as that doesn't exist ?
It's really difficult to test things 'at a distance'.
Tell him to copy+paste$beam_group**.**copy
rather than re-typing it - you must know how dumb some people can be ! -
He sent me his ruby console:
@unknownuser said:
new_group = $beam_group.copy
nil
new_group = $beam_group.copy
nilHe was supposed to enter:
@unknownuser said:
$beam_group
new_group = $beam_group.copyI have asked him to try some more things.
He says that he is on vacation, so we cannot try anything else until next week.@tig said:
I'll wager that he is misunderstanding and typing
$beam_group
or$beam_groupcopy
... and then getting 'nil' as that doesn't exist ?
It's really difficult to test things 'at a distance'.
Tell him to copy+paste$beam_group**.**copy
rather than re-typing it - you must know how dumb some people can be ! -
But simply typing
$beam_group
ORmy_copy=$beam_group.copy
will BOTH returnnil
IF$beam_group
is not being predefined ??
So the issue is that$beam_group
is not defined... NOT thatgroup.copy
is broken -
I do not get nil if I type in $xxx.copy where $xxx is not defined:
@unknownuser said:
$xxx
nil
$xxx.copy
Error: #<NoMethodError: undefined method `copy' for nil:NilClass>
(eval):95However, I agree that it would have been helpful if he had typed in $beam_group for me.
-
But if
$xxx
is defined [as something other thannil
] but not agroup
, BUT it's an object that can use a method.copy
- then it might returnnil
?
First you need to see if theSxxx
is a 'group'...
If it's a component-instance then copy it will also work if DC tools are loaded because that adds.copy
to the component-instance class too...
What other 'class' could it be that takes.copy
and returnsnil
?
Perhaps he has a third party script that ill-advisedly refines thegroup.copy
method and makes it returnnil
???
I have a pretty full house of scripts and Baregrep reveals a few with their own.copy
methods including my SKMtools that addsimage.copy
to mimicgroup.copy
; @Last's../Ruby_Tests/camera.rb
also has a.copy
method to copy a camera - as well asftools, fileutils
andSketchyPhysics
which also use.copy
methods, but these are entirely within their own classes outside of SUp's own ?? -
All Hail TIG!
I have key-shaped bruises on my forehead after spending a morning trying to work out why group.copy was returning nil when applied to a perfectly normal group.
TIG writes : "Perhaps he has a third party script that ill-advisedly refines the group.copy method and makes it return nil ???"
So I take out all scripts from my plugins directory and Hey Presto! suddenly group.copy works as advertised.
Gingerly replacing them and testing, I found the culprit to be Sketchy Physics 3.1
I take the file sketchyphysics.rb out of my plugins, group copy method works fine
I put it back in, group copy method returns nil
I take it out, copy works
I put it in, copy returns nil
I feel better.
So some keywords to help other poor souls :
group copy method failing returning nil not working stuffed buggered broken
I have sketchup 8.0.11752 free by the way
-
Enjoyed the thread and look forward to the maintenance revision of Sketchy Physics as I presume it was some of its redefinition/augmentation of classes which led to this snafu. I think removing SP should be part of any troubleshooting until it is made a bit tighter. Great program though.
-
This could have been my problem back in June as well.
Can you think of any way to lock a method stoat other rubies cannot override it. (This is mch worse than adding a new method to an existing class.) then SU could just lock aloof its methods.
-
The author of SketchyPhysics is aware of the issues and has said these will be addressed in the next update. It doesn't even use the changed group.copy method anyway
In the meantime rather than using
gcopy = group.copy
Which should return a reference to the new instance of the group, but might return 'nil' if SP messes with it... in your code consider something like this instead to side step it:
gcopy = group.parent.entities.add_instance(group.entities.parent, group.transformation)
This return the instance, placing the copy immediately over the original group, in the same context.Incidentally, you can also use this method to 'duplicate' a group inside another context, like:
gcopy = someother_entities.add_instance(group.entities.parent, group.transformation)
[Note: you might need to adjust 'transformation' depending on the contexts involved]
To 'move the group' addgroup.erase!; group = gcopy
- this will then appear that the group has moved into the new entities [like Edit>Cut...Edit>PasteInPlace].
The second step re-references 'group' to point to the new copy, as its 'id' etc will have changed too, this way it keeps an enduring reference, useful if you are to do something with it later on. -
@scottbattersby said:
I have key-shaped bruises on my forehead after spending a morning trying to work out why group.copy was returning nil when applied to a perfectly normal group.
TIG writes : "Perhaps he has a third party script that ill-advisedly refines the group.copy method and makes it return nil ???"
So I take out all scripts from my plugins directory and Hey Presto! suddenly group.copy works as advertised.
I was reading this thread and was just about to make a comment about group.copy being modified by some plugin - though I could not remember which one. Glad you pinned it down.
As TIG said, SketchyPhysics is being reworked to avoid such clashes.
-
@render plus said:
Can you think of any way to lock a method stoat other rubies cannot override it. (This is mch worse than adding a new method to an existing class.) then SU could just lock aloof its methods.
<span class="syntaxdefault"><br />module FooBar</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> def self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">hello</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> puts </span><span class="syntaxstring">'Hello world'</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;<br /></span><span class="syntaxcomment"># => nil<br /><br /></span><span class="syntaxdefault">FooBar</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">freeze<br /></span><span class="syntaxcomment"># => FooBar<br /><br /></span><span class="syntaxdefault">module FooBar</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> def self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">bye</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> puts </span><span class="syntaxstring">'Goodbye world'</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;<br /></span><span class="syntaxcomment"># => Error; #<TypeError; (eval);512; can't modify frozen object><br /># => (eval);512<br /><br /></span><span class="syntaxdefault">module FooBar</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> def self</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">hello</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> puts </span><span class="syntaxstring">'Hello evil world'</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;<br /></span><span class="syntaxcomment"># => Error; #<TypeError; (eval);512; can't modify frozen object><br /># => (eval);512<br /> </span><span class="syntaxdefault"></span>
-
hm... I'm tempted of adding a script that loads first that freezes the base ruby and SketchUp classes and modules just to see what happens. Could be useful to catch misbehaving plugins.
...hmm.... not sure what happens if you sub-class a frozen class....
-
@thomthom said:
...hmm.... not sure what happens if you sub-class a frozen class....
<span class="syntaxdefault"><br />class BaseFoo</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> def poke</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> puts </span><span class="syntaxstring">'arrrh!'</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;<br /></span><span class="syntaxcomment"># => nil<br /><br /></span><span class="syntaxdefault">BaseFoo</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">freeze<br /></span><span class="syntaxcomment"># => BaseFoo<br /><br /></span><span class="syntaxdefault">class BaseFoo</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> def prod</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> puts </span><span class="syntaxstring">'eeek!'</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;<br /></span><span class="syntaxcomment"># => Error; #<TypeError; (eval);512; can't modify frozen class><br /># => (eval);512<br /><br /></span><span class="syntaxdefault">class ChildFoo </span><span class="syntaxkeyword"><</span><span class="syntaxdefault"> BaseFoo</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> def prod</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> puts </span><span class="syntaxstring">'eeek!'</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;<br /></span><span class="syntaxcomment"># => nil<br /><br /></span><span class="syntaxdefault">x </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> ChildFoo</span><span class="syntaxkeyword">.new<br /></span><span class="syntaxcomment"># => #<ChildFoo;0x105ddb98><br /><br /></span><span class="syntaxdefault">x</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">prod<br /></span><span class="syntaxcomment"># => eeek!<br /># => nil<br /><br /></span><span class="syntaxdefault">x</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">poke<br /></span><span class="syntaxcomment"># => arrrh!<br /># => nil<br /><br /></span><span class="syntaxdefault">class ChildFoo</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> def prod</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> puts </span><span class="syntaxstring">'double-eeek!'</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;<br /></span><span class="syntaxcomment"># => nil<br /><br /></span><span class="syntaxdefault">class ChildFoo</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> def poke</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> puts </span><span class="syntaxstring">'cheeese!'</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;<br /></span><span class="syntaxcomment"># => nil<br /><br /></span><span class="syntaxdefault">class BaseFoo</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> def poke</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> puts </span><span class="syntaxstring">'moooo'</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> end</span><span class="syntaxkeyword">;<br /></span><span class="syntaxcomment"># => Error; #<TypeError; (eval);512; can't modify frozen class><br /># => (eval);512<br /> </span><span class="syntaxdefault"></span>
All good!
-
-
Here's a snippet I tried to lock down the API for debugging:
http://sketchucation.com/forums/viewtopic.php?f=180&t=48890#p439296 (new thread) -
@dan rathbun said:
Problem is that Ruby is designed to allow this by people who know what they are doing.
Yes - locking down the API out of the box can probably do more harm than anything.
But it does allow us to lock down for debugging. - See previous post.
-
@thomthom said:
hm... I'm tempted of adding a script that loads first that freezes the base ruby and SketchUp classes and modules just to see what happens. Could be useful to catch misbehaving plugins.
Problem is that Ruby is designed to allow this by people who know what they are doing.
Many of the Extended ruby Library files add needed methods to base classes, or modify some methods (RubyGems is an example that modifies the global
require
method, although I never understood why it really needed to do it.)Even though methods are objects, it is difficult to get a reference to an instance method within the class definition (very easy within an instance of the class.) So it is hard to freeze particular instance methods class-wide, without freezing the whole class or module. (Perhaps the gurus on the Ruby Forum know a trick?)
An alternative would possibly be (untested):
class Sketchup;;Group # Make a copy of method ;copy alias_method(;_copy_,;copy) def self.method_added(sym) # # callback called by Ruby when a new method is defined; # alias_method(;copy,;_copy_) if sym == ;copy # end end
EDIT:
method_added
is a class callback, so must be defined usingdef self.method_added(sym)
Advertisement