Sha256: c970f13b9ec15383d018d82a4d97d062c165f344dac207530bc1bf114bb6d470

Contents?: true

Size: 1.97 KB

Versions: 1

Compression:

Stored size: 1.97 KB

Contents

# encoding: utf-8
module EnumField
  class Builder

    METHODS = [:all, :names, :find_by_id, :find, :first, :last]

    def initialize(target)
      @target = target
      @next_id = 0
      @id2obj = {}
      @name2obj = {}
      @sorted = []
    end

    def member(name, options = {})
      obj, candidate_id = process_options(options)
      assign_id(obj, candidate_id)
      define_in_meta(name) { obj }
      save(name, obj)
      obj.freeze
    end

    def all
      @sorted.dup
    end

    def names
      @name2obj.keys
    end

    def find(id)
      find_by_id(id) or raise EnumField::ObjectNotFound
    end

    def find_by_id(id)
      case id
      when Integer, String, Float, Fixnum then 
        @id2obj[id.to_i]
      when Array then 
        id.inject([]) do |items, value|
          if value && value.respond_to?(:to_i)
            items << @id2obj[value.to_i]
          end

          items
        end
      end
    end

    def first; @sorted.first; end
    def last; @sorted.last; end

    private

    def define_in_meta(name, &block)
      metaclass = class << @target; self; end
      metaclass.send(:define_method, name, &block)
    end

    def assign_id(obj, candidate_id)
      id = new_id(candidate_id)
      obj.instance_variable_set(:@id, id)
    end

    def new_id(candidate)
      validate_candidate_id(candidate)
      candidate || find_next_id
    end

    def validate_candidate_id(id)
      raise EnumField::InvalidId.new(id) unless id.nil? || id.is_a?(Integer) && id > 0
      raise EnumField::RepeatedId.new(id) if @id2obj.has_key?(id)
    end

    def find_next_id
      @next_id += 1 while @id2obj.has_key?(@next_id) || @next_id <= 0
      @next_id
    end

    def process_options(options)
      raise EnumField::InvalidOptions unless options.reject {|k,v| k == :object || k == :id}.empty?
      [options[:object] || @target.new, options[:id]]
    end

    def save(name, obj)
      @id2obj[obj.id] = obj
      @sorted << obj
      @name2obj[name] = obj
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
galetahub-enum_field-0.3.0 lib/enum_field/builder.rb