selectable_attr 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/MIT-LICENSE +20 -0
- data/README +334 -0
- data/Rakefile +54 -0
- data/VERSION.yml +4 -0
- data/init.rb +1 -0
- data/install.rb +1 -0
- data/lib/selectable_attr/base.rb +304 -0
- data/lib/selectable_attr/enum.rb +168 -0
- data/lib/selectable_attr/version.rb +3 -0
- data/lib/selectable_attr.rb +6 -0
- data/selectable_attr.gemspec +54 -0
- data/spec/selectable_attr_base_alias_spec.rb +430 -0
- data/spec/selectable_attr_enum_spec.rb +129 -0
- data/spec/spec_helper.rb +11 -0
- data/tasks/selectable_attr_tasks.rake +18 -0
- data/uninstall.rb +1 -0
- metadata +73 -0
| @@ -0,0 +1,304 @@ | |
| 1 | 
            +
            # -*- coding: utf-8 -*-
         | 
| 2 | 
            +
            module SelectableAttr
         | 
| 3 | 
            +
              module Base
         | 
| 4 | 
            +
                def self.included(base)
         | 
| 5 | 
            +
                  base.extend(ClassMethods)
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
                
         | 
| 8 | 
            +
                ENUM_ARRAY_METHODS = {
         | 
| 9 | 
            +
                  :none => { 
         | 
| 10 | 
            +
                    :to_hash_array => Proc.new do |enum, attr_value|
         | 
| 11 | 
            +
                      value = (attr_value || []).map(&:to_s)
         | 
| 12 | 
            +
                      enum.to_hash_array do |hash|
         | 
| 13 | 
            +
                        hash[:select] = value.include?(hash[:id].to_s)
         | 
| 14 | 
            +
                      end
         | 
| 15 | 
            +
                    end,
         | 
| 16 | 
            +
                    
         | 
| 17 | 
            +
                    :to_attr_value => Proc.new do |enum, hash_array|
         | 
| 18 | 
            +
                      hash_array.select{|hash| hash[:select]}.map{|hash| hash[:id]}
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  },
         | 
| 21 | 
            +
                  
         | 
| 22 | 
            +
                  :comma_string => {
         | 
| 23 | 
            +
                    :to_hash_array => Proc.new do |enum, attr_value|
         | 
| 24 | 
            +
                      values = attr_value.is_a?(Array) ? attr_value.map{|v|v.to_s} :
         | 
| 25 | 
            +
                        (attr_value || '').split(',')
         | 
| 26 | 
            +
                      enum.to_hash_array do |hash|
         | 
| 27 | 
            +
                        hash[:select] = values.include?(hash[:id].to_s)
         | 
| 28 | 
            +
                      end
         | 
| 29 | 
            +
                    end,
         | 
| 30 | 
            +
                    
         | 
| 31 | 
            +
                    :to_attr_value => Proc.new do |enum, hash_array|
         | 
| 32 | 
            +
                      hash_array.select{|hash| hash[:select]}.map{|hash| hash[:id]}.join(',')
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  },
         | 
| 35 | 
            +
                  
         | 
| 36 | 
            +
                  
         | 
| 37 | 
            +
                  :binary_string => {
         | 
| 38 | 
            +
                    :to_hash_array => Proc.new do |enum, attr_value|
         | 
| 39 | 
            +
                      value = attr_value || ''
         | 
| 40 | 
            +
                      idx = 0
         | 
| 41 | 
            +
                      enum.to_hash_array do |hash|
         | 
| 42 | 
            +
                        hash[:select] = (value[idx, 1] == '1')
         | 
| 43 | 
            +
                        idx += 1
         | 
| 44 | 
            +
                      end
         | 
| 45 | 
            +
                    end,
         | 
| 46 | 
            +
                    
         | 
| 47 | 
            +
                    :to_attr_value => Proc.new do |enum, hash_array|
         | 
| 48 | 
            +
                      result = ''
         | 
| 49 | 
            +
                      hash_map = hash_array.inject({}){|dest, hash| dest[hash[:id]] = hash; dest}
         | 
| 50 | 
            +
                      enum.each do |entry|
         | 
| 51 | 
            +
                        hash = hash_map[entry.id]
         | 
| 52 | 
            +
                        result << (hash[:select] ? '1' : '0')
         | 
| 53 | 
            +
                      end
         | 
| 54 | 
            +
                      result
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
                  }
         | 
| 57 | 
            +
                }
         | 
| 58 | 
            +
                
         | 
| 59 | 
            +
                module ClassMethods
         | 
| 60 | 
            +
                  def single_selectable_attrs 
         | 
| 61 | 
            +
                    @single_selectable_attrs_hash ||= {};
         | 
| 62 | 
            +
                    @single_selectable_attrs_hash[self] ||= []
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                  
         | 
| 65 | 
            +
                  def multi_selectable_attrs 
         | 
| 66 | 
            +
                    @multi_selectable_attrs_hash ||= {};
         | 
| 67 | 
            +
                    @multi_selectable_attrs_hash[self] ||= []
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
                  
         | 
| 70 | 
            +
                  def selectable_attr_type_for(attr)
         | 
| 71 | 
            +
                    single_selectable_attrs.include?(attr.to_s) ? :single :
         | 
| 72 | 
            +
                    multi_selectable_attrs.include?(attr.to_s) ? :multi : nil
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                  
         | 
| 75 | 
            +
                  def enum(*args, &block)
         | 
| 76 | 
            +
                    process_definition(block, *args) do |enum, context|
         | 
| 77 | 
            +
                      self.single_selectable_attrs << context[:attr].to_s
         | 
| 78 | 
            +
                      define_enum_class_methods(context)
         | 
| 79 | 
            +
                      define_enum_instance_methods(context)
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                  alias_method :single_selectable_attr, :enum
         | 
| 83 | 
            +
                  alias_method :selectable_attr, :enum
         | 
| 84 | 
            +
                  
         | 
| 85 | 
            +
                  
         | 
| 86 | 
            +
                  def enum_array(*args, &block)
         | 
| 87 | 
            +
                    base_options = args.last.is_a?(Hash) ? args.pop : {}
         | 
| 88 | 
            +
                    args << base_options # .update({:attr_accessor => false})
         | 
| 89 | 
            +
                    process_definition(block, *args) do |enum, context|
         | 
| 90 | 
            +
                      self.multi_selectable_attrs << context[:attr].to_s
         | 
| 91 | 
            +
                      define_enum_class_methods(context)
         | 
| 92 | 
            +
                      define_enum_array_instance_methods(context)
         | 
| 93 | 
            +
                    end
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
                  alias_method :multi_selectable_attr, :enum_array
         | 
| 96 | 
            +
                  
         | 
| 97 | 
            +
                  def process_definition(block, *args)
         | 
| 98 | 
            +
                    base_options = args.last.is_a?(Hash) ? args.pop : {}
         | 
| 99 | 
            +
                    enum = base_options[:enum] || create_enum(&block)
         | 
| 100 | 
            +
                    args.each do |attr|
         | 
| 101 | 
            +
                      context = {
         | 
| 102 | 
            +
                        :enum => enum,
         | 
| 103 | 
            +
                        :attr_accessor => !has_attr(attr),
         | 
| 104 | 
            +
                        :attr => attr,
         | 
| 105 | 
            +
                        :base_name => enum_base_name(attr)
         | 
| 106 | 
            +
                      }.update(base_options)
         | 
| 107 | 
            +
                      define_enum(context)
         | 
| 108 | 
            +
                      define_accessor(context)
         | 
| 109 | 
            +
                      yield(enum, context)
         | 
| 110 | 
            +
                      unless enum.i18n_scope
         | 
| 111 | 
            +
                        paths = [:selectable_attrs] + self.name.to_s.split('::').map{|s| s.to_sym}
         | 
| 112 | 
            +
                        paths << attr.to_sym
         | 
| 113 | 
            +
                        enum.i18n_scope(*paths)
         | 
| 114 | 
            +
                      end
         | 
| 115 | 
            +
                    end
         | 
| 116 | 
            +
                    enum
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                  
         | 
| 119 | 
            +
                  def has_attr(attr)
         | 
| 120 | 
            +
                    return true if self.method_defined?(attr)
         | 
| 121 | 
            +
                    return false unless self.respond_to?(:columns)
         | 
| 122 | 
            +
                    if self.respond_to?(:connection) and self.respond_to?(:connected?)
         | 
| 123 | 
            +
                      begin
         | 
| 124 | 
            +
                        self.connection unless self.connected?
         | 
| 125 | 
            +
                      rescue Exception
         | 
| 126 | 
            +
                        return nil if !self.connected?
         | 
| 127 | 
            +
                      end
         | 
| 128 | 
            +
                    end
         | 
| 129 | 
            +
                    (respond_to?(:table_exists?) && self.table_exists?) ?
         | 
| 130 | 
            +
                      (self.columns || []).any?{|col|col.name.to_s == attr.to_s} : false
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
                  
         | 
| 133 | 
            +
                  def attr_enumeable_base(*args, &block)
         | 
| 134 | 
            +
                    @base_name_processor = block
         | 
| 135 | 
            +
                  end
         | 
| 136 | 
            +
                  
         | 
| 137 | 
            +
                  def enum_base_name(attr)
         | 
| 138 | 
            +
                    if @base_name_processor
         | 
| 139 | 
            +
                      @base_name_processor.call(attr).to_s
         | 
| 140 | 
            +
                    else
         | 
| 141 | 
            +
                      attr.to_s.gsub(selectable_attr_name_pattern, '')
         | 
| 142 | 
            +
                    end
         | 
| 143 | 
            +
                  end
         | 
| 144 | 
            +
                  
         | 
| 145 | 
            +
                  DEFAULT_SELECTABLE_ATTR_NAME_PATTERN = /(_cd$|_code$|_cds$|_codes$)/
         | 
| 146 | 
            +
                  
         | 
| 147 | 
            +
                  def selectable_attr_name_pattern
         | 
| 148 | 
            +
                    @selectable_attr_name_pattern ||= DEFAULT_SELECTABLE_ATTR_NAME_PATTERN
         | 
| 149 | 
            +
                  end
         | 
| 150 | 
            +
                  alias_method :enum_name_pattern, :selectable_attr_name_pattern
         | 
| 151 | 
            +
                  
         | 
| 152 | 
            +
                  def selectable_attr_name_pattern=(value)
         | 
| 153 | 
            +
                    @selectable_attr_name_pattern = value
         | 
| 154 | 
            +
                  end
         | 
| 155 | 
            +
                  alias_method :enum_name_pattern=, :selectable_attr_name_pattern=
         | 
| 156 | 
            +
                  
         | 
| 157 | 
            +
                  def create_enum(&block)
         | 
| 158 | 
            +
                    result = Enum.new
         | 
| 159 | 
            +
                    result.instance_eval(&block)
         | 
| 160 | 
            +
                    result
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
                  
         | 
| 163 | 
            +
                  def define_enum(context)
         | 
| 164 | 
            +
                    base_name = context[:base_name]
         | 
| 165 | 
            +
                    const_name = "#{base_name.upcase}_ENUM"
         | 
| 166 | 
            +
                    const_set(const_name, context[:enum]) unless const_defined?(const_name)
         | 
| 167 | 
            +
                  end
         | 
| 168 | 
            +
                  
         | 
| 169 | 
            +
                  def enum_for(attr)
         | 
| 170 | 
            +
                    base_name = enum_base_name(attr)
         | 
| 171 | 
            +
                    name = "#{base_name.upcase}_ENUM"
         | 
| 172 | 
            +
                    const_defined?(name) ? const_get(name) : nil
         | 
| 173 | 
            +
                  end
         | 
| 174 | 
            +
                  
         | 
| 175 | 
            +
                  def define_accessor(context)
         | 
| 176 | 
            +
                    attr = context[:attr]
         | 
| 177 | 
            +
                    return unless (instance_methods & [attr, "#{attr}="]).empty? 
         | 
| 178 | 
            +
                    if context[:attr_accessor]
         | 
| 179 | 
            +
                      if context[:default]
         | 
| 180 | 
            +
                        if respond_to?(:attr_accessor_with_default)
         | 
| 181 | 
            +
                          attr_accessor_with_default(attr, context[:default])
         | 
| 182 | 
            +
                        else
         | 
| 183 | 
            +
                          instance_var_name = "@#{attr}"
         | 
| 184 | 
            +
                          attr_writer(attr)
         | 
| 185 | 
            +
                          define_method(attr) do
         | 
| 186 | 
            +
                            value = instance_variable_get(instance_var_name)
         | 
| 187 | 
            +
                            instance_variable_set(instance_var_name, value = context[:default]) unless value
         | 
| 188 | 
            +
                            value
         | 
| 189 | 
            +
                          end
         | 
| 190 | 
            +
                        end
         | 
| 191 | 
            +
                      else
         | 
| 192 | 
            +
                        attr_accessor(attr)
         | 
| 193 | 
            +
                      end
         | 
| 194 | 
            +
                    else
         | 
| 195 | 
            +
                      if context[:default]
         | 
| 196 | 
            +
                        $stderr.puts "WARNING! :default option ignored for #{attr}"
         | 
| 197 | 
            +
                      end
         | 
| 198 | 
            +
                    end
         | 
| 199 | 
            +
                  end
         | 
| 200 | 
            +
                  
         | 
| 201 | 
            +
                  def define_enum_class_methods(context)
         | 
| 202 | 
            +
                    base_name = context[:base_name]
         | 
| 203 | 
            +
                    enum = context[:enum]
         | 
| 204 | 
            +
                    mod = Module.new
         | 
| 205 | 
            +
                    mod.module_eval do
         | 
| 206 | 
            +
                      define_method("#{base_name}_enum"){enum}
         | 
| 207 | 
            +
                      define_method("#{base_name}_hash_array"){enum.to_hash_array}
         | 
| 208 | 
            +
                      define_method("#{base_name}_entries"){enum.entries}
         | 
| 209 | 
            +
                      define_method("#{base_name}_options"){|*ids_or_keys|enum.options(*ids_or_keys)}
         | 
| 210 | 
            +
                      define_method("#{base_name}_ids"){|*ids_or_keys| enum.ids(*ids_or_keys)}
         | 
| 211 | 
            +
                      define_method("#{base_name}_keys"){|*ids_or_keys|enum.keys(*ids_or_keys)}
         | 
| 212 | 
            +
                      define_method("#{base_name}_names"){|*ids_or_keys|enum.names(*ids_or_keys)}
         | 
| 213 | 
            +
                      define_method("#{base_name}_key_by_id"){|id|enum.key_by_id(id)}
         | 
| 214 | 
            +
                      define_method("#{base_name}_id_by_key"){|key|enum.id_by_key(key)}
         | 
| 215 | 
            +
                      define_method("#{base_name}_name_by_id"){|id|enum.name_by_id(id)}
         | 
| 216 | 
            +
                      define_method("#{base_name}_name_by_key"){|key|enum.name_by_key(key)}
         | 
| 217 | 
            +
                      define_method("#{base_name}_entry_by_id"){|id|enum.entry_by_id(id)}
         | 
| 218 | 
            +
                      define_method("#{base_name}_entry_by_key"){|key|enum.entry_by_key(key)}
         | 
| 219 | 
            +
                    end
         | 
| 220 | 
            +
                    if convertors = ENUM_ARRAY_METHODS[context[:convert_with] || :none]
         | 
| 221 | 
            +
                      mod.module_eval do
         | 
| 222 | 
            +
                        define_method("#{base_name}_to_hash_array", convertors[:to_hash_array])
         | 
| 223 | 
            +
                        define_method("hash_array_to_#{base_name}", convertors[:to_attr_value])
         | 
| 224 | 
            +
                      end
         | 
| 225 | 
            +
                    end
         | 
| 226 | 
            +
                    self.extend(mod)
         | 
| 227 | 
            +
                  end
         | 
| 228 | 
            +
                  
         | 
| 229 | 
            +
                  def define_enum_instance_methods(context)
         | 
| 230 | 
            +
                    attr = context[:attr]
         | 
| 231 | 
            +
                    base_name = context[:base_name]
         | 
| 232 | 
            +
                    instance_methods = <<-EOS
         | 
| 233 | 
            +
                      def #{base_name}_key
         | 
| 234 | 
            +
                        self.class.#{base_name}_key_by_id(#{attr})
         | 
| 235 | 
            +
                      end
         | 
| 236 | 
            +
                      def #{base_name}_key=(key)
         | 
| 237 | 
            +
                        self.#{attr} = self.class.#{base_name}_id_by_key(key)
         | 
| 238 | 
            +
                      end
         | 
| 239 | 
            +
                      def #{base_name}_name
         | 
| 240 | 
            +
                        self.class.#{base_name}_name_by_id(#{attr})
         | 
| 241 | 
            +
                      end
         | 
| 242 | 
            +
                      def #{base_name}_entry
         | 
| 243 | 
            +
                        self.class.#{base_name}_entry_by_id(#{attr})
         | 
| 244 | 
            +
                      end
         | 
| 245 | 
            +
                      def #{base_name}_entry
         | 
| 246 | 
            +
                        self.class.#{base_name}_entry_by_id(#{attr})
         | 
| 247 | 
            +
                      end
         | 
| 248 | 
            +
                    EOS
         | 
| 249 | 
            +
                    self.module_eval(instance_methods)
         | 
| 250 | 
            +
                  end
         | 
| 251 | 
            +
                    
         | 
| 252 | 
            +
                  def define_enum_array_instance_methods(context)
         | 
| 253 | 
            +
                    attr = context[:attr]
         | 
| 254 | 
            +
                    base_name = context[:base_name]
         | 
| 255 | 
            +
                    # ActiveRecord::Baseから継承している場合は、基本カラムに対応するメソッドはない
         | 
| 256 | 
            +
                    self.module_eval(<<-"EOS")
         | 
| 257 | 
            +
                      def #{base_name}_ids
         | 
| 258 | 
            +
                        #{base_name}_hash_array_selected.map{|hash|hash[:id]}
         | 
| 259 | 
            +
                      end
         | 
| 260 | 
            +
                      def #{base_name}_ids=(ids)
         | 
| 261 | 
            +
                        ids = ids.split(',') if ids.is_a?(String)
         | 
| 262 | 
            +
                        ids = ids ? ids.map(&:to_s) : []
         | 
| 263 | 
            +
                        update_#{base_name}_hash_array{|hash|ids.include?(hash[:id].to_s)}
         | 
| 264 | 
            +
                      end
         | 
| 265 | 
            +
                      def #{base_name}_hash_array
         | 
| 266 | 
            +
                        self.class.#{base_name}_to_hash_array(self.class.#{base_name}_enum, #{attr})
         | 
| 267 | 
            +
                      end
         | 
| 268 | 
            +
                      def #{base_name}_hash_array=(hash_array)
         | 
| 269 | 
            +
                        self.#{attr} = self.class.hash_array_to_#{base_name}(self.class.#{base_name}_enum, hash_array)
         | 
| 270 | 
            +
                      end
         | 
| 271 | 
            +
                      def #{base_name}_hash_array_selected
         | 
| 272 | 
            +
                        #{base_name}_hash_array.select{|hash|!!hash[:select]}
         | 
| 273 | 
            +
                      end
         | 
| 274 | 
            +
                      def update_#{base_name}_hash_array(&block)
         | 
| 275 | 
            +
                        hash_array = #{base_name}_hash_array.map do |hash|
         | 
| 276 | 
            +
                          hash.merge(:select => yield(hash))
         | 
| 277 | 
            +
                        end
         | 
| 278 | 
            +
                        self.#{base_name}_hash_array = hash_array
         | 
| 279 | 
            +
                      end
         | 
| 280 | 
            +
                      def #{base_name}_keys
         | 
| 281 | 
            +
                        #{base_name}_hash_array_selected.map{|hash|hash[:key]}
         | 
| 282 | 
            +
                      end
         | 
| 283 | 
            +
                      def #{base_name}_keys=(keys)
         | 
| 284 | 
            +
                        update_#{base_name}_hash_array{|hash|keys.include?(hash[:key])}
         | 
| 285 | 
            +
                      end
         | 
| 286 | 
            +
                      def #{base_name}_selection
         | 
| 287 | 
            +
                        #{base_name}_hash_array.map{|hash|!!hash[:select]}
         | 
| 288 | 
            +
                      end
         | 
| 289 | 
            +
                      def #{base_name}_selection=(selection)
         | 
| 290 | 
            +
                        idx = -1
         | 
| 291 | 
            +
                        update_#{base_name}_hash_array{|hash| idx += 1; !!selection[idx]}
         | 
| 292 | 
            +
                      end
         | 
| 293 | 
            +
                      def #{base_name}_names
         | 
| 294 | 
            +
                        #{base_name}_hash_array_selected.map{|hash|hash[:name]}
         | 
| 295 | 
            +
                      end
         | 
| 296 | 
            +
                      def #{base_name}_entries
         | 
| 297 | 
            +
                        ids = #{base_name}_ids
         | 
| 298 | 
            +
                        self.class.#{base_name}_enum.select{|entry|ids.include?(entry.id)}
         | 
| 299 | 
            +
                      end
         | 
| 300 | 
            +
                    EOS
         | 
| 301 | 
            +
                  end
         | 
| 302 | 
            +
                end
         | 
| 303 | 
            +
              end
         | 
| 304 | 
            +
            end
         | 
| @@ -0,0 +1,168 @@ | |
| 1 | 
            +
            # -*- coding: utf-8 -*-
         | 
| 2 | 
            +
            module SelectableAttr
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              class Enum
         | 
| 5 | 
            +
                include Enumerable
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                class << self
         | 
| 8 | 
            +
                  def instances
         | 
| 9 | 
            +
                    @@instances ||= []
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
                
         | 
| 13 | 
            +
                def initialize(&block)
         | 
| 14 | 
            +
                  @entries = []
         | 
| 15 | 
            +
                  instance_eval(&block) if block_given?
         | 
| 16 | 
            +
                  SelectableAttr::Enum.instances << self
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                def entries
         | 
| 20 | 
            +
                  @entries
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                def each(&block)
         | 
| 24 | 
            +
                  entries.each(&block)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
                
         | 
| 27 | 
            +
                def define(id, key, name, options = nil, &block)
         | 
| 28 | 
            +
                  entry = Entry.new(self, id, key, name, options, &block)
         | 
| 29 | 
            +
                  entry.instance_variable_set(:@defined_in_code, true)
         | 
| 30 | 
            +
                  @entries << entry
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
                alias_method :entry, :define
         | 
| 33 | 
            +
                
         | 
| 34 | 
            +
                def i18n_scope(*path)
         | 
| 35 | 
            +
                  @i18n_scope = path unless path.empty?
         | 
| 36 | 
            +
                  @i18n_scope
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
                
         | 
| 39 | 
            +
                def match_entry(entry, value, *attrs)
         | 
| 40 | 
            +
                  attrs.any?{|attr| entry[attr].to_s == value.to_s}
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def entry_by(value, *attrs)
         | 
| 44 | 
            +
                  entries.detect{|entry| match_entry(entry, value, *attrs)} || Entry::NULL
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
                
         | 
| 47 | 
            +
                def entry_by_id(id)
         | 
| 48 | 
            +
                  entry_by(id, :id)
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
                
         | 
| 51 | 
            +
                def entry_by_key(key)
         | 
| 52 | 
            +
                  entry_by(key, :key)
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
                
         | 
| 55 | 
            +
                def entry_by_id_or_key(id_or_key)
         | 
| 56 | 
            +
                  entry_by(id_or_key, :id, :key)
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
                
         | 
| 59 | 
            +
                def entry_by_hash(attrs)
         | 
| 60 | 
            +
                  entries.detect{|entry| attrs.all?{|(attr, value)| entry[attr].to_s == value.to_s }} || Entry::NULL
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
                
         | 
| 63 | 
            +
                def [](arg)
         | 
| 64 | 
            +
                  arg.is_a?(Hash) ? entry_by_hash(arg) : entry_by_id_or_key(arg)
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
                
         | 
| 67 | 
            +
                def values(*args)
         | 
| 68 | 
            +
                  args = args.empty? ? [:name, :id] : args
         | 
| 69 | 
            +
                  result = entries.collect{|entry| args.collect{|arg| entry.send(arg) }}
         | 
| 70 | 
            +
                  (args.length == 1) ? result.flatten : result
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
                
         | 
| 73 | 
            +
                def map_attrs(attrs, *ids_or_keys)
         | 
| 74 | 
            +
                  if attrs.is_a?(Array)
         | 
| 75 | 
            +
                    ids_or_keys.empty? ? 
         | 
| 76 | 
            +
                      entries.map{|entry| attrs.map{|attr|entry.send(attr)}} : 
         | 
| 77 | 
            +
                      ids_or_keys.map do |id_or_key|
         | 
| 78 | 
            +
                        entry = entry_by_id_or_key(id_or_key)
         | 
| 79 | 
            +
                        attrs.map{|attr|entry.send(attr)}
         | 
| 80 | 
            +
                      end
         | 
| 81 | 
            +
                  else
         | 
| 82 | 
            +
                    attr = attrs
         | 
| 83 | 
            +
                    ids_or_keys.empty? ? 
         | 
| 84 | 
            +
                      entries.map(&attr.to_sym) : 
         | 
| 85 | 
            +
                      ids_or_keys.map{|id_or_key|entry_by_id_or_key(id_or_key).send(attr)}
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
                
         | 
| 89 | 
            +
                def ids(*ids_or_keys); map_attrs(:id, *ids_or_keys); end
         | 
| 90 | 
            +
                def keys(*ids_or_keys); map_attrs(:key, *ids_or_keys); end
         | 
| 91 | 
            +
                def names(*ids_or_keys); map_attrs(:name, *ids_or_keys); end
         | 
| 92 | 
            +
                def options(*ids_or_keys); map_attrs([:name, :id], *ids_or_keys); end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def key_by_id(id); entry_by_id(id).key; end
         | 
| 95 | 
            +
                def id_by_key(key); entry_by_key(key).id; end
         | 
| 96 | 
            +
                def name_by_id(id); entry_by_id(id).name; end
         | 
| 97 | 
            +
                def name_by_key(key); entry_by_key(key).name; end
         | 
| 98 | 
            +
                
         | 
| 99 | 
            +
                def find(options = nil, &block)
         | 
| 100 | 
            +
                  entries.detect{|entry| 
         | 
| 101 | 
            +
                      block_given? ? yield(entry) : entry.match?(options) 
         | 
| 102 | 
            +
                    } || Entry::NULL
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
                
         | 
| 105 | 
            +
                def to_hash_array
         | 
| 106 | 
            +
                  entries.map do |entry|
         | 
| 107 | 
            +
                    result = entry.to_hash
         | 
| 108 | 
            +
                    yield(result) if defined? yield
         | 
| 109 | 
            +
                    result
         | 
| 110 | 
            +
                  end
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
                
         | 
| 113 | 
            +
                def length
         | 
| 114 | 
            +
                  entries.length
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
                alias_method :size, :length
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                class Entry
         | 
| 119 | 
            +
                  BASE_ATTRS = [:id, :key, :name]
         | 
| 120 | 
            +
                  attr_reader :id, :key
         | 
| 121 | 
            +
                  attr_reader :defined_in_code
         | 
| 122 | 
            +
                  def initialize(enum, id, key, name, options = nil, &block)
         | 
| 123 | 
            +
                    @enum = enum
         | 
| 124 | 
            +
                    @id = id
         | 
| 125 | 
            +
                    @key = key
         | 
| 126 | 
            +
                    @name = name
         | 
| 127 | 
            +
                    @options = options
         | 
| 128 | 
            +
                    self.instance_eval(&block) if block
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
                  
         | 
| 131 | 
            +
                  attr_reader :name
         | 
| 132 | 
            +
                  
         | 
| 133 | 
            +
                  def [](option_key)
         | 
| 134 | 
            +
                    BASE_ATTRS.include?(option_key) ? send(option_key) :
         | 
| 135 | 
            +
                    @options ? @options[option_key] : nil
         | 
| 136 | 
            +
                  end
         | 
| 137 | 
            +
                  
         | 
| 138 | 
            +
                  def match?(options)
         | 
| 139 | 
            +
                    @options === options
         | 
| 140 | 
            +
                  end
         | 
| 141 | 
            +
                  
         | 
| 142 | 
            +
                  def null?
         | 
| 143 | 
            +
                    false
         | 
| 144 | 
            +
                  end
         | 
| 145 | 
            +
                  
         | 
| 146 | 
            +
                  def null_object?
         | 
| 147 | 
            +
                    self.null?
         | 
| 148 | 
            +
                  end
         | 
| 149 | 
            +
                  
         | 
| 150 | 
            +
                  def to_hash
         | 
| 151 | 
            +
                    (@options || {}).merge(:id => @id, :key => @key, :name => name)
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                  def inspect
         | 
| 155 | 
            +
                    # object_idを2倍にしているのは通常のinspectと合わせるためです。
         | 
| 156 | 
            +
                    '#<%s:%x @id=%s, @key=%s, @name=%s, @options=%s' % [
         | 
| 157 | 
            +
                      self.class.name, object_id * 2, id.inspect, key.inspect, name.inspect, @options.inspect]
         | 
| 158 | 
            +
                  end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                  NULL = new(nil, nil, nil, nil) do
         | 
| 161 | 
            +
                    def null?; true; end
         | 
| 162 | 
            +
                    def name; nil; end
         | 
| 163 | 
            +
                  end
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
                
         | 
| 166 | 
            +
              end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
            end
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Gem::Specification.new do |s|
         | 
| 4 | 
            +
              s.name = %q{selectable_attr}
         | 
| 5 | 
            +
              s.version = "0.3.7"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 8 | 
            +
              s.authors = ["Takeshi Akima"]
         | 
| 9 | 
            +
              s.date = %q{2009-08-17}
         | 
| 10 | 
            +
              s.description = %q{selectable_attr generates extra methods dynamically for attribute which has options}
         | 
| 11 | 
            +
              s.email = %q{akima@gmail.com}
         | 
| 12 | 
            +
              s.extra_rdoc_files = [
         | 
| 13 | 
            +
                "README"
         | 
| 14 | 
            +
              ]
         | 
| 15 | 
            +
              s.files = [
         | 
| 16 | 
            +
                ".gitignore",
         | 
| 17 | 
            +
                 "MIT-LICENSE",
         | 
| 18 | 
            +
                 "README",
         | 
| 19 | 
            +
                 "Rakefile",
         | 
| 20 | 
            +
                 "VERSION.yml",
         | 
| 21 | 
            +
                 "init.rb",
         | 
| 22 | 
            +
                 "install.rb",
         | 
| 23 | 
            +
                 "lib/selectable_attr.rb",
         | 
| 24 | 
            +
                 "lib/selectable_attr/base.rb",
         | 
| 25 | 
            +
                 "lib/selectable_attr/enum.rb",
         | 
| 26 | 
            +
                 "lib/selectable_attr/version.rb",
         | 
| 27 | 
            +
                 "selectable_attr.gemspec",
         | 
| 28 | 
            +
                 "spec/selectable_attr_base_alias_spec.rb",
         | 
| 29 | 
            +
                 "spec/selectable_attr_enum_spec.rb",
         | 
| 30 | 
            +
                 "spec/spec_helper.rb",
         | 
| 31 | 
            +
                 "tasks/selectable_attr_tasks.rake",
         | 
| 32 | 
            +
                 "uninstall.rb"
         | 
| 33 | 
            +
              ]
         | 
| 34 | 
            +
              s.homepage = %q{http://github.com/akm/selectable_attr/}
         | 
| 35 | 
            +
              s.rdoc_options = ["--charset=UTF-8"]
         | 
| 36 | 
            +
              s.require_paths = ["lib"]
         | 
| 37 | 
            +
              s.rubygems_version = %q{1.3.4}
         | 
| 38 | 
            +
              s.summary = %q{selectable_attr generates extra methods dynamically}
         | 
| 39 | 
            +
              s.test_files = [
         | 
| 40 | 
            +
                "spec/selectable_attr_base_alias_spec.rb",
         | 
| 41 | 
            +
                 "spec/selectable_attr_enum_spec.rb",
         | 
| 42 | 
            +
                 "spec/spec_helper.rb"
         | 
| 43 | 
            +
              ]
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              if s.respond_to? :specification_version then
         | 
| 46 | 
            +
                current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
         | 
| 47 | 
            +
                s.specification_version = 3
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
         | 
| 50 | 
            +
                else
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              else
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         |