Get_attributes() method

Hi., @DanRathbun

With reference to this thread (get_attributes() ),

i am facing the issue in the following code from the sketchucation post.

Sketchucation Protecting Dyanmic Components

the code as follows.

# module wrapper
module JcB
  extend self
  # simple cypher
  ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.freeze

  # generated with .split('').shuffle.join
  ENCODING = 'MOhqm0PnycUZeLdK8YvDCgNfb7FJtiHT52BrxoAkas9RWlXpEujSGI64VzQ31w'.freeze

  def encode(strng)
    if strng.class == String
      return strng.tr(ALPHABET, ENCODING)
    else
      return strng
    end
  end

  def decode(strng)
    if strng.class == String
      return strng.tr(ENCODING, ALPHABET)
    else
      return strng
    end
  end

  def break_dc
    m = Sketchup.active_model
    m.definitions.each do |d|
    next unless d.attribute_dictionaries && d.attribute_dictionaries['dynamic_attributes']
    d.get_attributes('dynamic_attributes').each do |a|
      d.set_attribute('encrypt_attributes', encode(a[0]), encode(a[1]))
      d.attribute_dictionaries.delete('dynamic_attributes')
    end

    d.instances.each do |i|
    next unless i.attribute_dictionaries && i.attribute_dictionaries['dynamic_attributes']
    i.get_attributes('dynamic_attributes').each do |a|
      i.set_attribute('encrypt_attributes', encode(a[0]), encode(a[1]))
      i.attribute_dictionaries.delete('dynamic_attributes')
    end end end
    m.definitions.purge_unused

    m = Sketchup.active_model
    m.definitions.each do |d|
      next unless d.attribute_dictionaries && d.attribute_dictionaries['encrypt_attributes']
      p d
      d.get_attributes('encrypt_attributes').each do |a|
        p a
      end end
  end

  def fix_dc
    m = Sketchup.active_model
    m.definitions.each do |d|
    next unless d.attribute_dictionaries && d.attribute_dictionaries['encrypt_attributes']
    d.get_attributes('encrypt_attributes').each do |a|
      d.set_attribute('dynamic_attributes', decode(a[0]), decode(a[1]))
      d.attribute_dictionaries.delete('encrypt_attributes')
    end

    d.instances.each do |i|
    next unless i.attribute_dictionaries && i.attribute_dictionaries['encrypt_attributes']
    i.get_attributes('encrypt_attributes').each do |a|
      i.set_attribute('dynamic_attributes', decode(a[0]), decode(a[1]))
      i.attribute_dictionaries.delete('encrypt_attributes')
    end end end
    m.definitions.purge_unused

    m = Sketchup.active_model
    m.definitions.each do |d|
      next unless d.attribute_dictionaries && d.attribute_dictionaries['dynamic_attributes']
      p d
      d.get_attributes('dynamic_attributes').each do |a|
        p a
      end end
  end
end

i am getting the following error.

Error: #<NoMethodError: undefined method get_attributes' for #<Sketchup::ComponentDefinition:0x000001fdfe4e29d0> Did you mean? get_attribute set_attribute> C:/Users/it/Desktop/encrypt/encrypt_dc.rb:30:in block in break_dc’
C:/Users/it/Desktop/encrypt/encrypt_dc.rb:28:in each' C:/Users/it/Desktop/encrypt/encrypt_dc.rb:28:in break_dc’

:in `' SketchUp:in `eval' => nil

Could you guide me how to sort this out.

I don’t think using ENCODING is wise as Ruby has a class of this name, ie: Encoding which is used for character encoding for files and strings.

I would suggest using the constant identifier CYPHER or CRYPTOGRAPH instead.

It is very clear by the error message:
"NoMethodError: undefined method 'get_attributes' for #<Sketchup::ComponentDefinition:...>"

So the Sketchup::ComponentDefinition class does not have a method named "get_attributes".

Your indentation is atrocious ! If you want help with your code, … ident correctly.

Don’t do … end end end This is crazy coding!


To iterate an attribute dictionary:

dict = obj.attribute_dictionary('dictionary_name')
next unless dict # nil if does not exist
dict.each do |key, val|
  # ... code using key and/or value
end

Dictionaries are hash-like objects consisting of key + value pairs. Trying to access via a[0] and a[1] is weird. Use the key and val block parameter pattern instead. (Ie, you doing things the hard way.)

Now … “why on earth” would you want to break Sketchup’s dynamic components extension by encoding all the dictionaries ?

Besides, the names of the dynamic attribute keys are all well known, so your cypher key will be easily found.

The SketchUp Ruby API has no method called get_attributes. It looks as it has been incorrectly defined in the shared namespace by one of the old shipped extensions.

You can instead try attribute_dictionary (API docs) to get one specific directory and then iterate over its content.

1 Like

It’s Advanced Camera Tools.

I never really understood why some coders what a hash from an attribute dictionary as they are basically the same kind of structure.

Also since the Enumerable module is mixed into AttributeDictionary class, a coder can simply do:

dict = obj.attribute_dictionary("some_name")
attr_hash =( dict ? dict.to_h : {} )

The only main reason I convert to hash is to easily get a JSON of a dictionary for writing out to a file …

dict = obj.attribute_dictionary("some_name")
json =( dict ? dict.to_h.to_json : {}.to_json )

(… that is if all the values types are recognized by the JSON library.)

1 Like

Thanks @DanRathbun, @ene_su noted your points.

Basically i am looking how to protect the dc attributes, formulas in the dynamic components to protect from modification by others without compromising the functionality of the DC’s.

ok noted the comments. will follow.

If you encrypt the attributes and delete the DC dictionaries then they become unusable “dumb” components that cannot be used with the Dynamic Components extension.

In order for them to be dynamic then your code would need to restore the DC dictionaries, at which time all a user needs to do is select and right-click a dynamic component and save it out to a file into order to circumvent your “protection”.
Ie, the API does not have an observer callback that fires when a definition (or copy) is saved out to storage, so you cannot prevent this.

Ok. Got it. Thanks