Get_attributes has stopped working

attribute
attributedictionary
attributes

#1

Today I was very surprized when an extension which I published over a year ago and has many users stopped working for me because a method called get_attributes, which used to return a hash of key value pairs if called on an entity which had attributes attached, is no longer defined. The evening before I upgraded Windows10 to the ‘Creators’ version and I wondered if that had broken a link to sketchup.rb or something? I’m guessing the method get_attributes is maybe defined there?


#2

I can’t find such a method in sketchup.rb (C:\Program Files\SketchUp\SketchUp 2017\Tools). I’m suspecying it’s defined by Dynamic Componenst which is known to be a shitty plugin do unconventional things like defining methods in the shared namespaces.


#3

is Dynamics Components up to date and turned on?

john


#4

Thank you for getting back so quickly. I know now that get_attributes is not in the API but I think it used to be or else I stumbled upon it. I’m just wondering why it stopped working and why no one else has been tripped up by it nor reported it to me.

John, Dynamic Components is enabled.


#5

Maybe Dynamic Components have been updated to not define its method in the shared namespace.


#6

that could be true. Then that will be a problem for my extension users. When I turned on SketchUp this morning a little ruby icon in a mini web window appeared in the top left corner of my SketchUp workspace. I’m thinking that was some kind of update. I can write my own get_attributes but it seemed silly to reinvent the wheel. I guess I’ll just have to do it.

I found get_attributes a handy method.


#7

If you do, just don’t define it in the shared Entity class. Modify the shared classes is a sin. Maybe you could play with refinements though.


#8

I’m not sure how to do it. I’ll mess around with it. It is a real shame for me. I have used it a lot. I might just pass the entities as an argument rather than use the dot operator. Then everything is kept inside my name space. It is a pain though. Any ideas?


#9

Fredo Tools wants to check if there up to date…

Dynamic Components was updated to run on CEF in v17…

it broke DC functionality on windows v16 for people, until they updated it using the Extension Warehouse…

your code should be checking if the user has DC turned on…

john


#10

thanks for reminding me that the ruby icon thing was fredo tools. I forgot that and it didn’t say what it was.
I definitely have DC turned on but still get_attributes doesn’t work. If it is a dependency then I think I will rewrite my code to avoid it. I’m wondering are there other methods that I could be using that are in the API? Hope not. I’m not even sure any more how I came across get_attributes. Probably simply stumbled upon it and thought ‘Great! I can use that.’


#11

I really don’t think it’s a good idea to in any way rely on another plugin (unless it’s a library specifically made to introduce the functionality you use).


#12

do normal DC’s work…

does ‘Component Attributes’ work…

have you updated it since the release of SU v17 [even if you didn’t upgrade]…

there have been other reports of this happening…

the DC rotation methods are often hijacked as well…

john


#13

@eneroth3, it is in the API under Entity…

#get_attribute(dict_name, key, default_value = nil) ⇒ Object

Returns value - the retrieved value

Parameters:
dict_name — The name of an attribute dictionary.
key — An attribute key.
default_value (optional) (defaults to: nil) — A default value to return if no attribute is found.
Returns:
 value - the retrieved value

but I’m sure DC’s mess with it…

john


#14

that is get_attribute which I know about. get_attributes worked like this
entity.get_attributes(“dict_name”)
and returned a hash of keys and values, the keys being the attribute key names and the values being the attribute values

I think I’ll try to write my own version of it although obviously it would be GREAT!! if the API just had. How about it you SketchUp people?


#15

Nope, that’s another method. get_attribute returns the value of a single attribute. get_attributes apperantly reurns the whole dictionary as a hash.

DC does something similar to this.

class Sketchup::Entity
    method get_attributes(dict_name)
        attribute_dictionaries[dict_name].to_h
    end
end

Note that this code isn’t identical. to_h only exists in newer Ruby versions.


#16

yes, my mistake, **attributes ** with the S is the DC version…

I forgot how much I try to avoid running DC because of all the errors it generates, so I

just looked for an example from one of mine and I seem to have just used long hand…

title = model.title
      model.set_attribute('JcB_SS', 'title', title)
      model.set_attribute('JcB_SS', 'face_count', @faces)
      bg = model.rendering_options['BackgroundColor']
      model.set_attribute('JcB_SS', 'bg', bg)
      hl = model.rendering_options['HighlightColor']
      model.set_attribute('JcB_SS', 'hl', hl)
      fc = model.rendering_options['ForegroundColor']
      model.set_attribute('JcB_SS', 'fc', fc)
      ed = model.rendering_options['EdgeDisplayMode']
      model.set_attribute('JcB_SS', 'ed', ed)

      sh = model.shadow_info['DisplayShadows']
      model.set_attribute('JcB_SS', 'sh', sh)
      fv = cam.fov
      model.set_attribute('JcB_SS', 'fv', fv)
      fl = cam.focal_length
      model.set_attribute('JcB_SS', 'fl', fl)
      pr = cam.perspective?
      model.set_attribute('JcB_SS', 'pr', pr)

#and later when the script finishes...
      hl = model.get_attribute('JcB_SS', 'hl')
      sh = model.get_attribute('JcB_SS', 'sh')
      fv = model.get_attribute('JcB_SS', 'fv')
      fl = model.get_attribute('JcB_SS', 'fl')
      pr = model.get_attribute('JcB_SS', 'pr')
      model.rendering_options['HighlightColor'] = hl
      model.rendering_options['ModelTransparency'] = false
      model.rendering_options['DisplaySectionPlanes'] = false
      model.rendering_options['DisplaySectionCuts'] = false
      model.shadow_info['DisplayShadows'] = sh

I guess I was to lazy to write a method at the time…

john


#17

Thank you for all the information. Lucky I haven’t used DC rotate or whatever.
Happy programming!


#18

(Moved to correct category: Developers > Ruby API )

Here is a method that creates a hash internally, then converts it to JSON.
It can be modified and renamed, omit the the call to load the json library, remove the last statement that creates the JSON String object, and replace it with a “return h” statement:

Basically this:

def self.get_attrs( obj, dict_name )
  d = obj.attribute_dictionary(dict_name,false)
  return false if d.nil?
  h = {} # create a hash
  d.each_pair {|k,v| h[k]=v }
  return h
end

#19

You can simulate the scenario of the objects getting such a method,
by defining singleton methods on specific objects:

# In your module or class, use this to add a 
#   hash getter method to specific objects:
def allow_attrs_as_hash( obj )
  if !obj.respond_to?(:get_attributes)
    obj.define_singleton_method(:get_attributes) do |dict_name|
      d = obj.attribute_dictionary(dict_name,false)
      h = {} # create a hash
      d.each_pair {|k,v| h[k]=v } if !d.nil?
      return h
    end
  end
end

Then elsewhere in your code, make your objects respond to a get_attributes call on a case by case basis:

allow_attrs_as_hash( face )
attr_hash = face.get_attributes("My_Dictionary")

Of, course I’d use shorter method names in actual use.

I might instead add a singleton .to_hash method to the specific dictionary objects I need to access in this way.


#20

First of all get_attributes returns empty hash, not nil, when the dictionary is missing (yes, it’s a very odd return value but it’s what it does).

Secondly and more importantly I would highly discourage this kind of monkey patching. I don’t even know if it would pass the EW review. If Camlaman were to define this method for the Entity class he is no better than the people who developed DC. Other developers might find the method, thinking it’s a part of the API (which is logical when it’s defined to the API’s namespace) and rely on it only to encounter errors that are hard to detect the day Camlaman’s plugin isn’t installed.

You don’t touch the API classes unless you have a really good reason for it, e.g. Aerilus LaunchUp plugin that hijacks Menu#add_item to know the names and Ruby calls for all menu items added by plugins. If you can manage without such a hack, don’t use such a hack.

EDIT: Sorry, misread the comment. Adding methods directly to the object is much better than monkey patching the class.