动态添加Atributte到Ruby对象

时间:2017-05-15 10:17:31

标签: arrays ruby object dynamic yaml

我有以下课程:

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(含)。例如,如果代码仅创建三个实体对象,则字段: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,是范围内的最后一个数字。

2 个答案:

答案 0 :(得分: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,就会在结尾处递增。

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

你可以改变这个

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

答案 1 :(得分:1)

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

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