【问题标题】:Add Atributte Dynamically to Ruby Object将属性动态添加到 Ruby 对象
【发布时间】:2017-10-14 02:03:03
【问题描述】:

我有以下课程:

class Entity
  attr_accessor :name, :internal_asn_number, :classification_id

  def initialize(name = nil,int_asn_no = 0,classification_id = nil)
    @name = name
    @internal_asn_number = int_asn_no
    @classification_id = classification_id

然后我有一个从 YAML 文件动态创建实体对象的方法,但是我希望字段 :internal_asn_number 也是动态的,它应该从 64512 到 65534(含)。例如,如果代码仅创建三个 Entities 对象,则字段 :internal_asn_number 应分别具有每个对象的值 64512、64513 和 64514。

我的代码如下:

#map of yaml fields from entities yaml conf files
FIELDS = {'ENTITY_ID'.to_sym => 'entity_identification','NAME'.to_sym => 'name','CLASS_ID'.to_sym => 'classification_id'}

def load_yaml   
  path = /mf370/Desktop/entities_yamls/ 
  entities = Array.new
  Dir.entries(path).select {|file|
    if !File.directory? path + file
      if File.extname(path + file) == '.yaml'
        config = YAML.load_file(path + file)

        asn=*(64512..65533)
        asn.each do |number|
        entity = Entity.new(config[FIELDS[:ENTITY_ID]][FIELDS[:NAME]],"#{number + 1}",
                            config[FIELDS[:ENTITY_ID]][FIELDS[:CLASS_ID]])
        entities << entity
        end

      end
    end

  }
  return entities
end

这段代码在输出中给了我几个问题,实体数组只有最后一个对象被保存了几次,它的:asn_internal_number 的值为 65533,是范围中的最后一个数字。

【问题讨论】:

    标签: arrays ruby object dynamic yaml


    【解决方案1】:

    避免为每个文件循环可能的asn_interal_number 值范围;相反,您可以使用不同的变量来跟踪当前的 asn_interal_number 并在分配下一个之前检查它;例如:

    FIELDS = {'ENTITY_ID'.to_sym => 'entity_identification','NAME'.to_sym => 'name','CLASS_ID'.to_sym => 'classification_id'}
    ASN_LIMIT = 65533
    
    def load_yaml  
      path = "/mf370/Desktop/entities_yamls/"
      entities = Array.new
      current_asn = 64512
    
      Dir.entries(path).select do |file|
        if !File.directory? path + file
          if File.extname(path + file) == '.yaml'
            if current_asn > ASN_LIMIT
              puts "Error, maximum asn numbers reached"
            else
              config = YAML.load_file(path + file)
              Entity.new(config[FIELDS[:ENTITY_ID]][FIELDS[:NAME]],"#{current_asn}",
                                  config[FIELDS[:ENTITY_ID]][FIELDS[:CLASS_ID]])
              entities << entity
              current_asn += 1
            end
          end
        end
      end
    
      return entities
    end
    

    您会注意到的第一件事是添加了一个 ASN_LIMIT 常量,用于检查是否还有可用的 asn 号码。

    ASN_LIMIT = 65533
    

    并且添加了current_asn,它跟踪分配的 las asn 编号(使用第一个可能的值初始化):

    current_asn = 64512
    

    最后,asn 循环被另一个 if 替换,如果达到 ASN_LIMIT 或分配 curret_asn 值,则会打印错误:

    接下来,current_asn 作为参数传递给Entity.new(不做任何修改):

    if current_asn > ASN_LIMIT
      puts "Error, maximum asn numbers reached"
    else
      config = YAML.load_file(path + file)
      Entity.new(config[FIELDS[:ENTITY_ID]][FIELDS[:NAME]],"#{current_asn}",
                          config[FIELDS[:ENTITY_ID]][FIELDS[:CLASS_ID]])
      entities << entity
      current_asn += 1
    end
    

    请注意,current_asn 在用于创建新的Entity 后会在末尾递增。


    以下 cmets 与您的问题无关,但会使您的代码更简单:

    你可以改变这个

    FIELDS = {'ENTITY_ID'.to_sym => 'entity_identification','NAME'.to_sym => 'name','CLASS_ID'.to_sym => 'classification_id'}
    

    FIELDS = { ENTITY_ID: 'entity_identification', NAME: 'name', CLASS_ID: 'classification_id' }
    

    并得到完全相同的结果:

    #=> {:ENTITY_ID=>"entity_identification", :NAME=>"name", :CLASS_ID=>"classification_id"}
    

    在 ruby​​ 中,使用 [] 而不是 Array.new 创建一个空数组更为惯用:

    entities = []
    

    而不是Dir.entries 使用Dir.glob,并且您不需要检查文件是否是目录或是否具有更正扩展名:

    Dir.glob("#{path}*.yaml") do |file|
      if current_asn > ASN_LIMIT
        # ...
      end
    end
    

    【讨论】:

    • 非常感谢@Gerry,我是 Ruby 编程新手,我真的需要学习不同的编程逻辑!!!!非常欢迎对我的代码进行所有更正!!再次感谢您!
    【解决方案2】:

    我同意之前的回答,但想建议像这样编写自己的课程:

    class Entity
      ASN_MIN = 64512
      ASN_MAX = 65533
    
      attr_accessor :name, :internal_asn_number, :classification_id
    
      def initialize(name = nil, classification_id = nil)
        @name = name
        @classification_id = classification_id
        set_internal_asn_number
      end
    
      private 
    
      def set_internal_asn_number
        @@last_free_asn ||= ASN_MIN
        raise 'No more free ASN number' if @@last_free_asn > ASN_MAX
        @internal_asn_number = @@last_free_asn
        @@last_free_asn += 1
      end  
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-12
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-05
      • 2015-08-27
      • 1970-01-01
      相关资源
      最近更新 更多