enumerize-1.0.0/0000755000004100000410000000000012560050170013537 5ustar www-datawww-dataenumerize-1.0.0/Rakefile0000644000004100000410000000047012560050170015205 0ustar www-datawww-data#!/usr/bin/env rake require "bundler/gem_tasks" require 'rake/testtask' require 'rspec/core/rake_task' Rake::TestTask.new do |t| t.libs << 'test' t.pattern = 'test/*_test.rb' t.verbose = true end RSpec::Core::RakeTask.new('default') do |t| t.pattern = 'test/rspec_spec.rb' end task :default => :test enumerize-1.0.0/Gemfile0000644000004100000410000000066012560050170015034 0ustar www-datawww-datasource 'https://rubygems.org' gemspec gem 'rake' gem 'minitest', '~> 5.5.1' gem 'rspec', :require => false gem 'rails', '4.2.0', :require => false gem 'sqlite3', :platform => [:ruby, :mswin, :mingw] gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby platforms :rbx do gem 'rubysl', '~> 2.0' gem 'psych' gem 'rubinius-developer_tools' gem 'rubysl-test-unit' end gem 'mongoid' gem 'simple_form' gem 'formtastic' enumerize-1.0.0/enumerize.gemspec0000644000004100000410000000156712560050170017120 0ustar www-datawww-data# -*- encoding: utf-8 -*- require File.expand_path('../lib/enumerize/version', __FILE__) Gem::Specification.new do |gem| gem.authors = ["Sergey Nartimov"] gem.email = "team@brainspec.com" gem.description = %q{Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper support} gem.summary = %q{Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper support} gem.homepage = "https://github.com/brainspec/enumerize" gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } gem.files = `git ls-files`.split("\n") gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") gem.name = "enumerize" gem.require_paths = ["lib"] gem.version = Enumerize::VERSION gem.required_ruby_version = '>= 1.9.3' gem.add_dependency('activesupport', '>= 3.2') end enumerize-1.0.0/MIT-LICENSE0000644000004100000410000000205212560050170015172 0ustar www-datawww-dataCopyright (c) 2012 Brainspec MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. enumerize-1.0.0/.travis.yml0000644000004100000410000000062012560050170015646 0ustar www-datawww-datalanguage: ruby services: - mongodb before_install: - gem install bundler gemfile: - Gemfile rvm: - 1.9.3 - 2.0.0 - 2.1 - 2.2 - jruby-19mode matrix: include: - rvm: 2.2 gemfile: Gemfile.rails40 - rvm: 2.2 gemfile: Gemfile.mongo_mapper notifications: email: recipients: - lest@brainspec.com - nashby@brainspec.com - dreamfall@brainspec.com enumerize-1.0.0/lib/0000755000004100000410000000000012560050170014305 5ustar www-datawww-dataenumerize-1.0.0/lib/enumerize.rb0000644000004100000410000000364112560050170016641 0ustar www-datawww-datarequire 'active_support/concern' require 'enumerize/version' module Enumerize autoload :Attribute, 'enumerize/attribute' autoload :AttributeMap, 'enumerize/attribute_map' autoload :Value, 'enumerize/value' autoload :Set, 'enumerize/set' autoload :Base, 'enumerize/base' autoload :Module, 'enumerize/module' autoload :Predicates, 'enumerize/predicates' autoload :Predicatable, 'enumerize/predicatable' autoload :ModuleAttributes, 'enumerize/module_attributes' autoload :ActiveRecordSupport, 'enumerize/activerecord' autoload :MongoidSupport, 'enumerize/mongoid' module Scope autoload :ActiveRecord, 'enumerize/scope/activerecord' autoload :Mongoid, 'enumerize/scope/mongoid' end def self.included(base) ActiveSupport::Deprecation.warn '`include Enumerize` was deprecated. Please use `extend Enumerize`.', caller extended(base) end def self.extended(base) base.send :include, Enumerize::Base base.extend Enumerize::Predicates if defined?(::ActiveRecord::Base) base.extend Enumerize::ActiveRecordSupport base.extend Enumerize::Scope::ActiveRecord end if defined?(::Mongoid::Document) base.extend Enumerize::MongoidSupport base.extend Enumerize::Scope::Mongoid end if defined?(::RailsAdmin) require 'enumerize/integrations/rails_admin' base.extend Enumerize::Integrations::RailsAdmin end if ::Module === base base.extend Enumerize::Base::ClassMethods base.extend Enumerize::ModuleAttributes end super end begin require 'simple_form' require 'enumerize/hooks/simple_form' require 'enumerize/form_helper' rescue LoadError end begin require 'formtastic' require 'enumerize/hooks/formtastic' rescue LoadError end begin require 'rspec/matchers' rescue LoadError else require 'enumerize/integrations/rspec' end end enumerize-1.0.0/lib/enumerize/0000755000004100000410000000000012560050170016310 5ustar www-datawww-dataenumerize-1.0.0/lib/enumerize/predicatable.rb0000644000004100000410000000070712560050170021260 0ustar www-datawww-datamodule Enumerize module Predicatable def respond_to_missing?(method, include_private=false) predicate_method?(method) || super end private def method_missing(method, *args, &block) if predicate_method?(method) predicate_call(method[0..-2], *args, &block) else super end end def predicate_method?(method) method[-1] == '?' && @attr.values.include?(method[0..-2]) end end end enumerize-1.0.0/lib/enumerize/integrations/0000755000004100000410000000000012560050170021016 5ustar www-datawww-dataenumerize-1.0.0/lib/enumerize/integrations/rails_admin.rb0000644000004100000410000000054412560050170023630 0ustar www-datawww-datamodule Enumerize module Integrations module RailsAdmin def enumerize(name, options={}) super _enumerize_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name}_enum self.class.enumerized_attributes[:#{name}].values.map{|v| [v.text, v.value]} end RUBY end end end end enumerize-1.0.0/lib/enumerize/integrations/rspec/0000755000004100000410000000000012560050170022132 5ustar www-datawww-dataenumerize-1.0.0/lib/enumerize/integrations/rspec/matcher.rb0000644000004100000410000000362712560050170024112 0ustar www-datawww-datamodule Enumerize module Integrations module RSpec class Matcher attr_accessor :attr, :values, :subject, :default def initialize(attr) self.attr = attr end def in(*values) self.values = values.map(&:to_s).sort self end def with_default(default) self.default = default.to_s self end def failure_message message = " expected :#{attr} to allow value#{values.size == 1 ? nil : 's'}: #{quote_values(values)}," message += " but it allows #{quote_values(enumerized_values)} instead" if default && !matches_default_value? message = " expected :#{attr} to have #{default.inspect} as default value," message += " but it sets #{enumerized_default.inspect} instead" end message end def description description = "enumerize :#{attr} in: #{quote_values(values)}" description += " with #{default.inspect} as default value" if default description end def matches?(subject) self.subject = subject matches = true matches &= matches_attributes? matches &= matches_default_value? if default matches end private def matches_attributes? values == enumerized_values end def matches_default_value? default == enumerized_default end def enumerized_values @enumerized_values ||= attributes[attr.to_s].values.sort end def enumerized_default @enumerized_default ||= attributes[attr.to_s].default_value end def attributes subject.class.enumerized_attributes.attributes end def quote_values(values) values.map(&:inspect).join(', ') end end end end end enumerize-1.0.0/lib/enumerize/integrations/rspec.rb0000644000004100000410000000045712560050170022465 0ustar www-datawww-datarequire 'enumerize/integrations/rspec/matcher' module Enumerize module Integrations module RSpec def enumerize(attr) ::Enumerize::Integrations::RSpec::Matcher.new(attr) end end end end module RSpec module Matchers include Enumerize::Integrations::RSpec end end enumerize-1.0.0/lib/enumerize/predicates.rb0000644000004100000410000000313012560050170020755 0ustar www-datawww-datarequire 'active_support/core_ext/module/delegation' module Enumerize # Predicate methods. # # Basic usage: # # class User # extend Enumerize # enumerize :sex, in: %w(male female), predicates: true # end # # user = User.new # # user.male? # => false # user.female? # => false # # user.sex = 'male' # # user.male? # => true # user.female? # => false # # Using prefix: # # class User # extend Enumerize # enumerize :sex, in: %w(male female), predicates: { prefix: true } # end # # user = User.new # user.sex = 'female' # user.sex_female? # => true # # Use only and except options to specify what values create # predicate methods for. module Predicates def enumerize(name, options={}) super if options[:predicates] Builder.new(enumerized_attributes[name], options[:predicates]).build(_enumerize_module) end end class Builder def initialize(attr, options) @attr = attr @options = options.is_a?(Hash) ? options : {} end def values values = @attr.values if @options[:only] values &= Array(@options[:only]).map(&:to_s) end if @options[:except] values -= Array(@options[:except]).map(&:to_s) end values end def names values.map { |v| "#{v}?" } end def build(klass) klass.delegate(*names, to: @attr.name, prefix: @options[:prefix], allow_nil: true) end end end end enumerize-1.0.0/lib/enumerize/set.rb0000644000004100000410000000257712560050170017443 0ustar www-datawww-datarequire 'active_support/core_ext/module/delegation' module Enumerize class Set include Enumerable include Predicatable attr_reader :values def initialize(obj, attr, values) @obj = obj @attr = attr @values = [] if values.respond_to?(:each) values.each do |input| value = @attr.find_value(input) if value && !@values.include?(value) @values << value end end end end def <<(value) @values << value mutate! end alias_method :push, :<< delegate :each, :empty?, :size, to: :values def to_ary @values.to_a end def texts @values.collect { |value| value.text } end delegate :join, to: :to_ary def ==(other) other.size == size && other.all? { |v| @values.include?(@attr.find_value(v)) } end alias_method :eql?, :== def include?(value) @values.include?(@attr.find_value(value)) end def delete(value) @values.delete(@attr.find_value(value)) mutate! end def inspect "#" end def encode_with(coder) coder.represent_object(Array, @values) end private def predicate_call(value) include?(value) end def mutate! @values = @obj.public_send("#{@attr.name}=", @values).values end end end enumerize-1.0.0/lib/enumerize/value.rb0000644000004100000410000000174012560050170017753 0ustar www-datawww-datarequire 'i18n' module Enumerize class Value < String include Predicatable attr_reader :value def initialize(attr, name, value=nil) @attr = attr @value = value.nil? ? name.to_s : value super(name.to_s) end def text I18n.t(i18n_keys[0], :default => i18n_keys[1..-1]) end def ==(other) super(other.to_s) || value == other end def encode_with(coder) coder.represent_object(self.class.superclass, @value) end private def predicate_call(value) value == self end def i18n_keys @i18n_keys ||= begin i18n_keys = i18n_scopes i18n_keys << [:"enumerize.defaults.#{@attr.name}.#{self}"] i18n_keys << [:"enumerize.#{@attr.name}.#{self}"] i18n_keys << self.underscore.humanize # humanize value if there are no translations i18n_keys.flatten end end def i18n_scopes @attr.i18n_scopes.map { |s| :"#{s}.#{self}" } end end end enumerize-1.0.0/lib/enumerize/module.rb0000644000004100000410000000106112560050170020120 0ustar www-datawww-datamodule Enumerize class Module < ::Module attr_reader :_class_methods def initialize super @_class_methods = ::Module.new @_dependents = [] @_dependent_evals = [] end def included(klass) klass.extend _class_methods @_dependent_evals.each do |block| klass.instance_eval(&block) end @_dependents << klass end def dependent_eval(&block) @_dependents.each do |klass| klass.instance_eval(&block) end @_dependent_evals << block end end end enumerize-1.0.0/lib/enumerize/hooks/0000755000004100000410000000000012560050170017433 5ustar www-datawww-dataenumerize-1.0.0/lib/enumerize/hooks/simple_form.rb0000644000004100000410000000241712560050170022300 0ustar www-datawww-datarequire 'active_support/concern' module Enumerize module Hooks module SimpleFormBuilderExtension extend ActiveSupport::Concern included do alias_method_chain :input, :enumerize alias_method_chain :input_field, :enumerize end def input_with_enumerize(attribute_name, options={}, &block) add_input_options_for_enumerized_attribute(attribute_name, options) input_without_enumerize(attribute_name, options, &block) end def input_field_with_enumerize(attribute_name, options={}) add_input_options_for_enumerized_attribute(attribute_name, options) input_field_without_enumerize(attribute_name, options) end private def add_input_options_for_enumerized_attribute(attribute_name, options) klass = object.class if klass.respond_to?(:enumerized_attributes) && (attr = klass.enumerized_attributes[attribute_name]) options[:collection] ||= attr.options if attr.kind_of?(Enumerize::Multiple) && options[:as] != :check_boxes options[:input_html] = options.fetch(:input_html, {}).merge(:multiple => true) end end end end end end ::SimpleForm::FormBuilder.send :include, Enumerize::Hooks::SimpleFormBuilderExtension enumerize-1.0.0/lib/enumerize/hooks/formtastic.rb0000644000004100000410000000146112560050170022135 0ustar www-datawww-datarequire 'active_support/concern' module Enumerize module Hooks module FormtasticFormBuilderExtension extend ActiveSupport::Concern included do alias_method_chain :input, :enumerize end def input_with_enumerize(method, options={}) klass = object.class if klass.respond_to?(:enumerized_attributes) && (attr = klass.enumerized_attributes[method]) options[:collection] ||= attr.options if attr.kind_of?(Enumerize::Multiple) && options[:as] != :check_boxes options[:input_html] = options.fetch(:input_html, {}).merge(:multiple => true) end end input_without_enumerize(method, options) end end end end ::Formtastic::FormBuilder.send :include, Enumerize::Hooks::FormtasticFormBuilderExtension enumerize-1.0.0/lib/enumerize/hooks/uniqueness.rb0000644000004100000410000000121012560050170022151 0ustar www-datawww-datarequire 'active_support/concern' module Enumerize module Hooks module UniquenessValidator extend ActiveSupport::Concern included do alias_method_chain :validate_each, :enumerize end def validate_each_with_enumerize(record, name, value) if record.class.respond_to?(:enumerized_attributes) && (attr = record.class.enumerized_attributes[name]) value = attr.find_value(value).try(:value) end validate_each_without_enumerize(record, name, value) end end end end ::ActiveRecord::Validations::UniquenessValidator.send :include, Enumerize::Hooks::UniquenessValidator enumerize-1.0.0/lib/enumerize/version.rb0000644000004100000410000000005112560050170020316 0ustar www-datawww-datamodule Enumerize VERSION = "1.0.0" end enumerize-1.0.0/lib/enumerize/scope/0000755000004100000410000000000012560050170017421 5ustar www-datawww-dataenumerize-1.0.0/lib/enumerize/scope/mongoid.rb0000644000004100000410000000165412560050170021410 0ustar www-datawww-datamodule Enumerize module Scope module Mongoid def enumerize(name, options={}) super _enumerize_module.dependent_eval do if self < ::Mongoid::Document if options[:scope] _define_mongoid_scope_methods!(name, options) end end end end private def _define_mongoid_scope_methods!(name, options) scope_name = options[:scope] == true ? "with_#{name}" : options[:scope] define_singleton_method scope_name do |*values| values = enumerized_attributes[name].find_values(*values).map(&:value) self.in(name => values) end if options[:scope] == true define_singleton_method "without_#{name}" do |*values| values = enumerized_attributes[name].find_values(*values).map(&:value) not_in(name => values) end end end end end end enumerize-1.0.0/lib/enumerize/scope/activerecord.rb0000644000004100000410000000177712560050170022434 0ustar www-datawww-datamodule Enumerize module Scope module ActiveRecord def enumerize(name, options={}) super _enumerize_module.dependent_eval do if self < ::ActiveRecord::Base if options[:scope] _define_activerecord_scope_methods!(name, options) end end end end private def _define_activerecord_scope_methods!(name, options) scope_name = options[:scope] == true ? "with_#{name}" : options[:scope] define_singleton_method scope_name do |*values| values = enumerized_attributes[name].find_values(*values).map(&:value) values = values.first if values.size == 1 where(name => values) end if options[:scope] == true define_singleton_method "without_#{name}" do |*values| values = enumerized_attributes[name].find_values(*values).map(&:value) where(arel_table[name].not_in(values)) end end end end end end enumerize-1.0.0/lib/enumerize/module_attributes.rb0000644000004100000410000000035512560050170022373 0ustar www-datawww-datamodule Enumerize module ModuleAttributes def included(base) base.extend Enumerize base.send :include, _enumerize_module enumerized_attributes.add_dependant base.enumerized_attributes super end end end enumerize-1.0.0/lib/enumerize/mongoid.rb0000644000004100000410000000043312560050170020271 0ustar www-datawww-datamodule Enumerize module MongoidSupport def enumerize(name, options={}) super _enumerize_module.dependent_eval do if self < ::Mongoid::Document after_initialize :_set_default_value_for_enumerized_attributes end end end end end enumerize-1.0.0/lib/enumerize/base.rb0000644000004100000410000000577612560050170017566 0ustar www-datawww-datamodule Enumerize module Base def self.included(base) base.extend ClassMethods if base.respond_to?(:validate) base.validate :_validate_enumerized_attributes end class << base if (method_defined?(:inherited) || private_method_defined?(:inherited)) && !private_method_defined?(:inherited_without_enumerized) alias_method :inherited_without_enumerized, :inherited private :inherited_without_enumerized end alias_method :inherited, :inherited_with_enumerized end end module ClassMethods def enumerize(name, options={}) attr = Attribute.new(self, name, options) enumerized_attributes << attr unless methods.include?(attr.name) _enumerize_module._class_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{attr.name} enumerized_attributes[:#{attr.name}] end RUBY end attr.define_methods!(_enumerize_module) end def enumerized_attributes @enumerized_attributes ||= AttributeMap.new end def inherited_with_enumerized(subclass) enumerized_attributes.add_dependant subclass.enumerized_attributes if respond_to?(:inherited_without_enumerized, true) inherited_without_enumerized subclass end end private def _enumerize_module @_enumerize_module ||= begin mod = Module.new include mod mod end end end def initialize(*) super _set_default_value_for_enumerized_attributes end def read_attribute_for_validation(key) key = key.to_s if _enumerized_values_for_validation.has_key?(key) _enumerized_values_for_validation[key] else super end end private def _enumerized_values_for_validation @_enumerized_values_for_validation ||= {} end def _validate_enumerized_attributes self.class.enumerized_attributes.each do |attr| value = read_attribute_for_validation(attr.name) next if value.blank? if attr.kind_of? Multiple errors.add attr.name unless value.respond_to?(:all?) && value.all? { |v| v.blank? || attr.find_value(v) } else errors.add attr.name, :inclusion unless attr.find_value(value) end end end def _set_default_value_for_enumerized_attributes self.class.enumerized_attributes.each do |attr| if respond_to?(attr.name) attr_value = public_send(attr.name) else next end value_for_validation = _enumerized_values_for_validation[attr.name.to_s] if (!attr_value || attr_value.empty?) && (!value_for_validation || value_for_validation.empty?) value = attr.default_value if value.respond_to?(:call) value = value.arity == 0 ? value.call : value.call(self) end public_send("#{attr.name}=", value) end end end end end enumerize-1.0.0/lib/enumerize/activerecord.rb0000644000004100000410000000224712560050170021314 0ustar www-datawww-datamodule Enumerize module ActiveRecordSupport def enumerize(name, options={}) super _enumerize_module.dependent_eval do if self < ::ActiveRecord::Base include InstanceMethods # Since Rails use `allocate` method on models and initializes them with `init_with` method. # This way `initialize` method is not being called, but `after_initialize` callback always gets triggered. after_initialize :_set_default_value_for_enumerized_attributes # https://github.com/brainspec/enumerize/issues/111 require 'enumerize/hooks/uniqueness' end end end module InstanceMethods # https://github.com/brainspec/enumerize/issues/74 def write_attribute(attr_name, value) if self.class.enumerized_attributes[attr_name] _enumerized_values_for_validation[attr_name.to_s] = value end super end # Support multiple enumerized attributes def becomes(klass) became = super klass.enumerized_attributes.each do |attr| became.send("#{attr.name}=", send(attr.name)) end became end end end end enumerize-1.0.0/lib/enumerize/attribute_map.rb0000644000004100000410000000115512560050170021477 0ustar www-datawww-datamodule Enumerize class AttributeMap attr_reader :attributes def initialize @attributes = {} @dependants = [] end def [](name) @attributes[name.to_s] end def <<(attr) @attributes[attr.name.to_s] = attr @dependants.each do |dependant| dependant << attr end end def each @attributes.each_pair do |_name, attr| yield attr end end def empty? @attributes.empty? end def add_dependant(dependant) @dependants << dependant each do |attr| dependant << attr end end end end enumerize-1.0.0/lib/enumerize/attribute.rb0000644000004100000410000001207712560050170020647 0ustar www-datawww-datamodule Enumerize class Attribute attr_reader :name, :values, :default_value, :i18n_scope def initialize(klass, name, options={}) raise ArgumentError, ':in option is required' unless options[:in] raise ArgumentError, ':scope option does not work with option :multiple' if options[:multiple] && options[:scope] extend Multiple if options[:multiple] @klass = klass @name = name.to_sym value_class = options.fetch(:value_class, Value) @values = Array(options[:in]).map { |v| value_class.new(self, *v) } @value_hash = Hash[@values.map { |v| [v.value.to_s, v] }] @value_hash.merge! Hash[@values.map { |v| [v.to_s, v] }] if options[:i18n_scope] raise ArgumentError, ':i18n_scope option accepts only String or Array of strings' unless Array(options[:i18n_scope]).all? { |s| s.is_a?(String) } @i18n_scope = options[:i18n_scope] end if options[:default] @default_value = find_default_value(options[:default]) raise ArgumentError, 'invalid default value' unless @default_value end end def find_default_value(value) if value.respond_to?(:call) value else find_value(value) end end def find_value(value) @value_hash[value.to_s] unless value.nil? end def find_values(*values) values.map { |value| find_value(value) }.compact end def i18n_scopes @i18n_scopes ||= if i18n_scope scopes = Array(i18n_scope) elsif @klass.respond_to?(:model_name) scopes = ["enumerize.#{@klass.model_name.i18n_key}.#{name}"] else [] end end def options(options = {}) values = if options.empty? @values else raise ArgumentError, 'Options cannot have both :only and :except' if options[:only] && options[:except] only = Array(options[:only]).map(&:to_s) except = Array(options[:except]).map(&:to_s) @values.reject do |value| if options[:only] !only.include?(value) elsif options[:except] except.include?(value) end end end values.map { |v| [v.text, v.to_s] } end def respond_to_missing?(method, include_private=false) @value_hash.include?(method.to_s) || super end def define_methods!(mod) mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} if defined?(super) self.class.enumerized_attributes[:#{name}].find_value(super) elsif respond_to?(:read_attribute) self.class.enumerized_attributes[:#{name}].find_value(read_attribute(:#{name})) else if defined?(@#{name}) self.class.enumerized_attributes[:#{name}].find_value(@#{name}) else @#{name} = nil end end end def #{name}=(new_value) allowed_value_or_nil = self.class.enumerized_attributes[:#{name}].find_value(new_value) allowed_value_or_nil = allowed_value_or_nil.value unless allowed_value_or_nil.nil? if defined?(super) super allowed_value_or_nil elsif respond_to?(:write_attribute, true) write_attribute '#{name}', allowed_value_or_nil else @#{name} = allowed_value_or_nil end _enumerized_values_for_validation['#{name}'] = new_value.nil? ? nil : new_value.to_s allowed_value_or_nil end def #{name}_text self.#{name} && self.#{name}.text end def #{name}_value self.#{name} && self.#{name}.value end RUBY end private def method_missing(method) if @value_hash.include?(method.to_s) find_value(method) else super end end end module Multiple def find_default_value(value) if value.respond_to?(:call) value else find_values(*value) end end def define_methods!(mod) mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} unless defined?(@_#{name}_enumerized_set) if defined?(super) self.#{name} = super elsif respond_to?(:read_attribute) self.#{name} = read_attribute(:#{name}) else if defined?(@#{name}) self.#{name} = @#{name} else self.#{name} = [] end end end @_#{name}_enumerized_set end def #{name}=(values) @_#{name}_enumerized_set = Enumerize::Set.new(self, self.class.enumerized_attributes[:#{name}], values) raw_values = #{name}.values.map(&:value) if defined?(super) super raw_values elsif respond_to?(:write_attribute, true) write_attribute '#{name}', raw_values else @#{name} = raw_values end _enumerized_values_for_validation['#{name}'] = values.respond_to?(:map) ? values.map(&:to_s) : values #{name} end RUBY end end end enumerize-1.0.0/Gemfile.rails400000644000004100000410000000065612560050170016316 0ustar www-datawww-datasource 'https://rubygems.org' gemspec gem 'rake' gem 'minitest', '~> 4.1' gem 'rspec', :require => false gem 'rails', '4.0.1', :require => false gem 'sqlite3', :platform => [:ruby, :mswin, :mingw] gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby platforms :rbx do gem 'rubysl', '~> 2.0' gem 'psych' gem 'rubinius-developer_tools' gem 'rubysl-test-unit' end gem 'mongoid' gem 'simple_form' gem 'formtastic' enumerize-1.0.0/metadata.yml0000644000004100000410000000620312560050170016043 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: enumerize version: !ruby/object:Gem::Version version: 1.0.0 platform: ruby authors: - Sergey Nartimov autorequire: bindir: bin cert_chain: [] date: 2015-08-02 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: activesupport requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '3.2' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '3.2' description: Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper support email: team@brainspec.com executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - ".travis.yml" - CHANGELOG.md - Gemfile - Gemfile.mongo_mapper - Gemfile.rails40 - MIT-LICENSE - README.md - Rakefile - enumerize.gemspec - lib/enumerize.rb - lib/enumerize/activerecord.rb - lib/enumerize/attribute.rb - lib/enumerize/attribute_map.rb - lib/enumerize/base.rb - lib/enumerize/hooks/formtastic.rb - lib/enumerize/hooks/simple_form.rb - lib/enumerize/hooks/uniqueness.rb - lib/enumerize/integrations/rails_admin.rb - lib/enumerize/integrations/rspec.rb - lib/enumerize/integrations/rspec/matcher.rb - lib/enumerize/module.rb - lib/enumerize/module_attributes.rb - lib/enumerize/mongoid.rb - lib/enumerize/predicatable.rb - lib/enumerize/predicates.rb - lib/enumerize/scope/activerecord.rb - lib/enumerize/scope/mongoid.rb - lib/enumerize/set.rb - lib/enumerize/value.rb - lib/enumerize/version.rb - test/activerecord_test.rb - test/attribute_map_test.rb - test/attribute_test.rb - test/base_test.rb - test/formtastic_test.rb - test/module_attributes_test.rb - test/mongo_mapper_test.rb - test/mongoid_test.rb - test/multiple_test.rb - test/predicates_test.rb - test/rails_admin_test.rb - test/rspec_matcher_test.rb - test/rspec_spec.rb - test/set_test.rb - test/simple_form_test.rb - test/support/mock_controller.rb - test/support/view_test_helper.rb - test/test_helper.rb - test/value_test.rb homepage: https://github.com/brainspec/enumerize licenses: [] metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 1.9.3 required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.4.7 signing_key: specification_version: 4 summary: Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper support test_files: - test/activerecord_test.rb - test/attribute_map_test.rb - test/attribute_test.rb - test/base_test.rb - test/formtastic_test.rb - test/module_attributes_test.rb - test/mongo_mapper_test.rb - test/mongoid_test.rb - test/multiple_test.rb - test/predicates_test.rb - test/rails_admin_test.rb - test/rspec_matcher_test.rb - test/rspec_spec.rb - test/set_test.rb - test/simple_form_test.rb - test/support/mock_controller.rb - test/support/view_test_helper.rb - test/test_helper.rb - test/value_test.rb enumerize-1.0.0/test/0000755000004100000410000000000012560050170014516 5ustar www-datawww-dataenumerize-1.0.0/test/mongo_mapper_test.rb0000644000004100000410000000267612560050170020600 0ustar www-datawww-datarequire 'test_helper' begin silence_warnings do require 'mongo_mapper' end MongoMapper.connection = Mongo::Connection.new('localhost', 27017) MongoMapper.database = 'enumerize-test-suite-of-mongomapper' describe Enumerize do class MongoMapperUser include MongoMapper::Document extend Enumerize key :sex key :role enumerize :sex, :in => %w[male female] enumerize :role, :in => %w[admin user], :default => 'user' end before { $VERBOSE = nil } after { $VERBOSE = true } let(:model) { MongoMapperUser } it 'sets nil if invalid value is passed' do user = model.new user.sex = :invalid user.sex.must_equal nil end it 'saves value' do model.delete_all user = model.new user.sex = :female user.save! user.sex.must_equal 'female' end it 'loads value' do model.delete_all model.create!(:sex => :male) store_translations(:en, :enumerize => {:sex => {:male => 'Male'}}) do user = model.first user.sex.must_equal 'male' user.sex_text.must_equal 'Male' end end it 'has default value' do model.new.role.must_equal 'user' end it 'validates inclusion' do user = model.new user.role = 'wrong' user.wont_be :valid? end it 'assigns value on loaded record' do model.delete_all model.create!(:sex => :male) user = model.first user.sex = :female user.sex.must_equal 'female' end end rescue LoadError # Skip end enumerize-1.0.0/test/attribute_map_test.rb0000644000004100000410000000262112560050170020743 0ustar www-datawww-datarequire 'test_helper' module Enumerize class AttributeMapTest < MiniTest::Spec subject { AttributeMap.new } def make_attr(name) Attribute.new(nil, name, :in => %[a b]) end it 'empty when no attrs' do subject.must_be_empty end it 'not empty when attr added' do subject << make_attr(:a) subject.wont_be_empty end it 'iterates over added attrs' do attr_1 = make_attr(:a) attr_2 = make_attr(:b) subject << attr_1 subject << attr_2 count = 0 actual = [] subject.each do |element| count += 1 actual << element end count.must_equal 2 actual.must_equal [attr_1, attr_2] end it 'reads attribute by name' do attr = make_attr(:a) subject << attr subject[:a].must_equal attr end it 'reads attribute by name using string' do attr = make_attr(:a) subject << attr subject['a'].must_equal attr end it 'updates dependants' do attr = make_attr(:a) dependant = MiniTest::Mock.new dependant.expect(:<<, nil, [attr]) subject.add_dependant dependant subject << attr dependant.verify end it 'adds attrs to dependant' do attr = make_attr(:a) subject << attr dependant = AttributeMap.new subject.add_dependant dependant dependant[:a].must_equal attr end end end enumerize-1.0.0/test/simple_form_test.rb0000644000004100000410000000620512560050170020421 0ustar www-datawww-datarequire 'test_helper' require 'simple_form/version' class SimpleFormSpec < MiniTest::Spec include ViewTestHelper include SimpleForm::ActionViewExtensions::FormHelper class Thing < Struct.new(:name) extend ActiveModel::Naming include ActiveModel::Conversion def persisted? false end end class User < Struct.new(:sex, :age) extend ActiveModel::Naming include ActiveModel::Conversion extend Enumerize enumerize :sex, :in => [:male, :female] def persisted? false end end class Post < Struct.new(:category, :title) extend ActiveModel::Naming include ActiveModel::Conversion extend Enumerize enumerize :categories, :in => [:music, :games], :multiple => true def persisted? false end end let(:user) { User.new } let(:post) { Post.new } it 'renders select with enumerized values using input_field' do concat(simple_form_for(user) do |f| f.input_field(:sex) end) assert_select 'select option[value=male]' assert_select 'select option[value=female]' end it 'renders select with enumerized values' do concat(simple_form_for(user) do |f| f.input(:sex) end) assert_select 'select option[value=male]' assert_select 'select option[value=female]' end it 'renders multiple select with enumerized values' do concat(simple_form_for(post) do |f| f.input(:categories) end) assert_select 'select[multiple=multiple]' assert_select 'select option[value=music]' assert_select 'select option[value=games]' end it 'renders multiple select with selected enumerized value' do post.categories << :music concat(simple_form_for(post) do |f| f.input(:categories) end) assert_select 'select[multiple=multiple]' assert_select 'select option[value=music][selected=selected]' assert_select 'select option[value=games][selected=selected]', count: 0 end it 'renders checkboxes with enumerized values' do concat(simple_form_for(post) do |f| f.input(:categories, as: :check_boxes) end) assert_select 'select[multiple=multiple]', count: 0 assert_select 'input[type=checkbox][value=music]' assert_select 'input[type=checkbox][value=games]' end it 'renders checkboxes with selected enumerized value' do post.categories << :music concat(simple_form_for(post) do |f| f.input(:categories, as: :check_boxes) end) assert_select 'input[type=checkbox][value=music][checked=checked]' assert_select 'input[type=checkbox][value=games][checked=checked]', count: 0 end it 'renders radio buttons with enumerated values' do concat(simple_form_for(user) do |f| f.input(:sex, :as => :radio_buttons) end) assert_select 'input[type=radio][value=male]' assert_select 'input[type=radio][value=female]' end it 'does not affect not enumerized attributes' do concat(simple_form_for(user) do |f| f.input(:age) end) assert_select 'input.string' end it 'does not affect not enumerized classes' do concat(simple_form_for(Thing.new) do |f| f.input(:name) end) assert_select 'input.string' end end enumerize-1.0.0/test/rspec_matcher_test.rb0000644000004100000410000000441712560050170020727 0ustar www-datawww-datarequire 'test_helper' require 'enumerize/integrations/rspec' describe Enumerize::Integrations::RSpec do class Should include Enumerize::Integrations::RSpec end let(:klass) do Class.new do extend Enumerize end end let(:should) { Should.new } let(:object) { klass.new } describe '#description' do before do klass.enumerize(:sex, :in => [:male, :female]) end it 'returns description without default value' do matcher = should.enumerize(:sex).in(:male, :female) matcher.description.must_equal 'enumerize :sex in: "female", "male"' end it 'returns description with default value' do matcher = should.enumerize(:sex).in(:male, :female).with_default(:male) matcher.description.must_equal 'enumerize :sex in: "female", "male" with "male" as default value' end end describe '#matches?' do before do klass.enumerize(:sex, :in => [:male, :female]) end it 'returns true' do matcher = should.enumerize(:sex).in(:male, :female) matcher.matches?(object).must_equal true end it 'returns false' do matcher = should.enumerize(:sex).in(:bar) matcher.matches?(object).must_equal false end end describe '#failure_message' do before do klass.enumerize(:sex, :in => [:male, :female], :default => :male) end it 'returns failure message for invalid :in option' do matcher = should.enumerize(:sex).in(:bar) matcher.subject = object expected = ' expected :sex to allow value: "bar", but it allows "female", "male" instead' matcher.failure_message.must_equal expected end it 'returns failure message for invalid :with_default option' do matcher = should.enumerize(:sex).in(:male, :female).with_default(:foo) matcher.subject = object expected = ' expected :sex to have "foo" as default value, but it sets "male" instead' matcher.failure_message.must_equal expected end it 'returns failure message for ivalid :in option with default value' do matcher = should.enumerize(:sex).in(:bar).with_default(:male) matcher.subject = object expected = ' expected :sex to allow value: "bar", but it allows "female", "male" instead' matcher.failure_message.must_equal expected end end end enumerize-1.0.0/test/rails_admin_test.rb0000644000004100000410000000126512560050170020370 0ustar www-datawww-datarequire 'test_helper' class RailsAdminSpec < MiniTest::Spec let(:klass) do Class.new do extend Enumerize end end let(:object) { klass.new } it 'defines enum method' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do klass.enumerize(:foo, in: [:a, :b]) object.foo_enum.must_equal [['a text', 'a'], ['b text', 'b']] end end it 'defines enum properly for custom values enumerations' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do klass.enumerize(:foo, in: {:a => 1, :b => 2}) object.foo_enum.must_equal [['a text', 1], ['b text', 2]] end end end enumerize-1.0.0/test/module_attributes_test.rb0000644000004100000410000000244712560050170021644 0ustar www-datawww-datarequire 'test_helper' class ModuleAttributesSpec < MiniTest::Spec it 'inherits attribute from the module' do mod = Module.new do extend Enumerize enumerize :sex, :in => %w[male female], :default => 'male' end klass = Class.new klass.send :include, mod klass.enumerized_attributes[:sex].must_be_instance_of Enumerize::Attribute klass.new.sex.must_equal 'male' klass.sex.must_be_instance_of Enumerize::Attribute end it 'uses new attributes from the module' do mod = Module.new do extend Enumerize end klass = Class.new klass.send :include, mod mod.enumerize :sex, :in => %w[male female], :default => 'male' klass.enumerized_attributes[:sex].must_be_instance_of Enumerize::Attribute klass.new.sex.must_equal 'male' klass.sex.must_be_instance_of Enumerize::Attribute end it 'validates attributes' do mod = Module.new do extend Enumerize enumerize :sex, :in => %w[male female] end klass = Class.new do include ActiveModel::Validations include mod def self.model_name ActiveModel::Name.new(self, nil, 'name') end end object = klass.new object.sex = 'wrong' object.wont_be :valid? object.errors[:sex].must_include 'is not included in the list' end end enumerize-1.0.0/test/formtastic_test.rb0000644000004100000410000000610712560050170020261 0ustar www-datawww-datarequire 'test_helper' Formtastic::FormBuilder.action_class_finder = Formtastic::ActionClassFinder Formtastic::FormBuilder.input_class_finder = Formtastic::InputClassFinder class FormtasticSpec < MiniTest::Spec include ViewTestHelper include Formtastic::Helpers::FormHelper class Thing < Struct.new(:name) extend ActiveModel::Naming include ActiveModel::Conversion def persisted? false end end class User < Struct.new(:sex, :age) extend ActiveModel::Naming include ActiveModel::Conversion extend Enumerize enumerize :sex, :in => [:male, :female] def persisted? false end end class Post < Struct.new(:category, :title) extend ActiveModel::Naming include ActiveModel::Conversion extend Enumerize enumerize :categories, :in => [:music, :games], :multiple => true def persisted? false end end before { $VERBOSE = nil } after { $VERBOSE = true } let(:user) { User.new } let(:post) { Post.new } it 'renders select with enumerized values' do concat(semantic_form_for(user) do |f| f.input :sex end) assert_select 'select option[value=male]' assert_select 'select option[value=female]' end it 'renders multiple select with enumerized values' do concat(semantic_form_for(post) do |f| f.input(:categories) end) assert_select 'select[multiple=multiple]' assert_select 'select option[value=music]' assert_select 'select option[value=games]' end it 'renders multiple select with selected enumerized value' do post.categories << :music concat(semantic_form_for(post) do |f| f.input(:categories) end) assert_select 'select[multiple=multiple]' assert_select 'select option[value=music][selected=selected]' assert_select 'select option[value=games][selected=selected]', count: 0 end it 'renders checkboxes with enumerized values' do concat(semantic_form_for(post) do |f| f.input(:categories, as: :check_boxes) end) assert_select 'select[multiple=multiple]', count: 0 assert_select 'input[type=checkbox][value=music]' assert_select 'input[type=checkbox][value=games]' end it 'renders checkboxes with selected enumerized value' do post.categories << :music concat(semantic_form_for(post) do |f| f.input(:categories, as: :check_boxes) end) assert_select 'input[type=checkbox][value=music][checked=checked]' assert_select 'input[type=checkbox][value=games][checked=checked]', count: 0 end it 'renders radio buttons with enumerized values' do concat(semantic_form_for(user) do |f| f.input :sex, :as => :radio end) assert_select 'input[type=radio][value=male]' assert_select 'input[type=radio][value=female]' end it 'does not affect not enumerized attributes' do concat(semantic_form_for(user) do |f| f.input(:age) end) assert_select 'input[type=text]' end it 'does not affect not enumerized classes' do concat(semantic_form_for(Thing.new) do |f| f.input(:name) end) assert_select 'input[type=text]' end end enumerize-1.0.0/test/predicates_test.rb0000644000004100000410000000267612560050170020240 0ustar www-datawww-datarequire 'test_helper' describe Enumerize::Predicates do let(:klass) do Class.new do extend Enumerize end end let(:object) { klass.new } it 'creates predicate methods' do klass.enumerize(:foo, in: %w(a b), predicates: true) object.must_respond_to :a? object.must_respond_to :b? end it 'creates predicate methods on multiple attribute' do klass.enumerize(:foo, in: %w(a b), predicates: true, multiple: true) object.must_respond_to :a? object.must_respond_to :b? end it 'checks values' do klass.enumerize(:foo, in: %w(a b), predicates: true) object.foo = 'a' object.a?.must_equal true object.b?.must_equal false end it 'checks values on multiple attribute' do klass.enumerize(:foo, in: %w(a b), predicates: true, multiple: true) object.foo << :a object.a?.must_equal true object.b?.must_equal false end it 'prefixes methods' do klass.enumerize(:foo, in: %w(a b), predicates: { prefix: 'bar' }) object.wont_respond_to :a? object.wont_respond_to :b? object.must_respond_to :bar_a? object.must_respond_to :bar_b? end it 'accepts only option' do klass.enumerize(:foo, in: %w(a b), predicates: { only: :a }) object.must_respond_to :a? object.wont_respond_to :b? end it 'accepts except option' do klass.enumerize(:foo, in: %w(a b), predicates: { except: :a }) object.wont_respond_to :a? object.must_respond_to :b? end end enumerize-1.0.0/test/set_test.rb0000644000004100000410000000610312560050170016675 0ustar www-datawww-datarequire 'test_helper' require 'yaml' describe Enumerize::Set do let(:klass) do Class.new do extend Enumerize enumerize :foo, :in => %w(a b c), :multiple => true end end let(:object) { klass.new } def build_set(values) @set = Enumerize::Set.new(object, klass.foo, values) end def set @set end def assert_called(object, method) called = false object.singleton_class.class_eval do define_method method do |*args, &block| called = true super(*args, &block) end end yield assert called, "Expected ##{method} to be called" end before do build_set %w(a) end it 'equals to other set' do set.must_equal Enumerize::Set.new(nil, klass.foo, %w(a)) end it 'equals to array' do set.must_equal %w(a) end it 'equals to array of symbols' do set.must_equal [:a] end it 'has unique values' do set << :a set.must_equal %w(a) end it 'equals to array with different value order' do set << :b set.must_equal %w(b a) end it "isn't equal to a part of values" do set << :b set.wont_equal %w(a) end describe '#push' do it 'appends values' do set.push :b set.must_include :b end it 'reassigns attribute' do assert_called object, :foo= do set.push :b end end end describe '#delete' do it 'deletes value' do set.delete :a set.wont_include :a end it 'reassigns attribute' do assert_called object, :foo= do set.delete :a end end end describe '#inspect' do it 'returns custom string' do set << :b set.inspect.must_equal '#' end end describe '#to_ary' do it 'returns array' do set.to_ary.must_be_instance_of Array end end describe '#texts' do it 'returns array of text values' do set.texts.must_equal ['A'] end end describe '#join' do it 'joins values' do set << :b set.join(', ').must_equal 'a, b' end end describe 'boolean methods comparison' do it 'returns true if value equals method' do set << :a set.a?.must_equal true end it 'returns false if value does not equal method' do set << :a set.b?.must_equal false end it 'raises NoMethodError if there are no values like boolean method' do proc { set.some_method? }.must_raise NoMethodError end it 'raises ArgumentError if arguments are passed' do proc { set.a?('<3') }.must_raise ArgumentError end it 'responds to methods for existing values' do set.must_respond_to :a? set.must_respond_to :b? set.must_respond_to :c? end it 'returns a method object' do set.method(:a?).must_be_instance_of Method end it 'does not respond to a method for not existing value' do set.wont_respond_to :some_method? end end describe 'serialization' do it 'is serialized to yaml as array' do set << :a assert_equal YAML.dump(%w(a)), YAML.dump(set) end end end enumerize-1.0.0/test/test_helper.rb0000644000004100000410000000163112560050170017362 0ustar www-datawww-datarequire 'minitest/autorun' require 'minitest/spec' require 'active_support/core_ext/kernel/reporting' require 'active_model' require 'rails' begin require 'mongoid' rescue LoadError end module RailsAdmin end require 'simple_form' SimpleForm.setup {} require 'formtastic' module EnumerizeTest class Application < Rails::Application config.active_support.deprecation = :stderr config.active_support.test_order = :random config.eager_load = false config.secret_key_base = 'secret' end end EnumerizeTest::Application.initialize! $VERBOSE=true require 'enumerize' Dir["#{File.dirname(__FILE__)}/support/*.rb"].each do |file| require file end module MiscHelpers def store_translations(locale, translations, &block) begin I18n.backend.store_translations locale, translations yield ensure I18n.reload! end end end class MiniTest::Spec include MiscHelpers end enumerize-1.0.0/test/rspec_spec.rb0000644000004100000410000000045112560050170017171 0ustar www-datawww-datarequire 'rails' require 'enumerize' require 'rspec' class RSpecUser extend Enumerize enumerize :sex, in: [:male, :female], default: :male end describe RSpecUser do it { should enumerize(:sex).in(:male, :female) } it { should enumerize(:sex).in(:male, :female).with_default(:male) } end enumerize-1.0.0/test/mongoid_test.rb0000644000004100000410000000625012560050170017541 0ustar www-datawww-datarequire 'test_helper' begin silence_warnings do require 'mongoid' end Mongoid.configure do |config| config.sessions = { :default => { :database => 'enumerize-test-suite', hosts: ['127.0.0.1:27017'] } } config.use_utc = true config.include_root_in_json = true end describe Enumerize do class MongoidUser include Mongoid::Document extend Enumerize field :sex field :role enumerize :sex, :in => %w[male female], scope: true enumerize :status, :in => %w[notice warning error], scope: true enumerize :role, :in => %w[admin user], :default => 'user', scope: :having_role enumerize :mult, :in => %w[one two three four], :multiple => true end before { $VERBOSE = nil } after { $VERBOSE = true } let(:model) { MongoidUser } it 'sets nil if invalid value is passed' do user = model.new user.sex = :invalid user.sex.must_equal nil end it 'saves value' do model.delete_all user = model.new user.sex = :female user.save! user.sex.must_equal 'female' end it 'loads value' do model.delete_all model.create!(:sex => :male) store_translations(:en, :enumerize => {:sex => {:male => 'Male'}}) do user = model.first user.sex.must_equal 'male' user.sex_text.must_equal 'Male' end end it 'has default value' do model.new.role.must_equal 'user' end it 'uses after_initialize callback to set default value' do model.delete_all model.create!(sex: 'male', role: nil) user = model.where(sex: 'male').first user.role.must_equal 'user' end it 'validates inclusion' do user = model.new user.role = 'wrong' user.wont_be :valid? end it 'assigns value on loaded record' do model.delete_all model.create!(:sex => :male) user = model.first user.sex = :female user.sex.must_equal 'female' end it 'loads multiple properly' do model.delete_all model.create!(:mult => ['one', 'two']) user = model.first user.mult.to_a.must_equal ['one', 'two'] end it 'adds scope' do model.delete_all user_1 = model.create!(sex: :male, role: :admin) user_2 = model.create!(sex: :female, role: :user) model.with_sex(:male).to_a.must_equal [user_1] model.with_sex(:female).to_a.must_equal [user_2] model.with_sex(:male, :female).to_set.must_equal [user_1, user_2].to_set model.without_sex(:male).to_a.must_equal [user_2] model.without_sex(:female).to_a.must_equal [user_1] model.without_sex(:male, :female).to_a.must_equal [] model.having_role(:admin).to_a.must_equal [user_1] model.having_role(:user).to_a.must_equal [user_2] end it 'chains scopes' do model.delete_all user_1 = model.create!(status: :notice) user_2 = model.create!(status: :warning) user_3 = model.create!(status: :error) model.with_status(:notice, :warning).with_status(:notice, :error).to_a.must_equal [user_1] model.with_status(:notice, :warning).union.with_status(:notice, :error).to_a.must_equal [user_1, user_2, user_3] end it 'ignores not enumerized values that passed to the scope method' do model.delete_all model.with_sex(:foo).must_equal [] end end rescue LoadError # Skip end enumerize-1.0.0/test/base_test.rb0000644000004100000410000001225612560050170017022 0ustar www-datawww-datarequire 'test_helper' describe Enumerize::Base do let(:klass) do Class.new do extend Enumerize end end let(:subklass) do Class.new(klass) end let(:object) { klass.new } it 'returns nil when not set' do klass.enumerize(:foo, :in => [:a, :b]) object.foo.must_equal nil end it 'returns value that was set' do klass.enumerize(:foo, :in => [:a, :b]) object.foo = :a object.foo.must_equal 'a' end it 'returns translation' do store_translations(:en, :enumerize => {:foo => {:a => 'a text'}}) do klass.enumerize(:foo, :in => [:a, :b]) object.foo = :a object.foo.text.must_equal 'a text' object.foo_text.must_equal 'a text' object.foo_text.must_equal 'a text' end end it 'returns nil as translation when value is nil' do store_translations(:en, :enumerize => {:foo => {:a => 'a text'}}) do klass.enumerize(:foo, :in => [:a, :b]) object.foo_text.must_equal nil end end it 'scopes translation by i18 key' do def klass.model_name name = "ExampleClass" def name.i18n_key 'example_class' end name end store_translations(:en, :enumerize => {:example_class => {:foo => {:a => 'a text scoped'}}}) do klass.enumerize(:foo, :in => [:a, :b]) object.foo = :a object.foo.text.must_equal 'a text scoped' object.foo_text.must_equal 'a text scoped' end end it 'returns humanized value if there are no translations' do store_translations(:en, :enumerize => {}) do klass.enumerize(:foo, :in => [:a, :b]) object.foo = :a object.foo_text.must_equal 'A' end end it 'stores value as string' do klass.enumerize(:foo, :in => [:a, :b]) object.foo = :a object.instance_variable_get(:@foo).must_be_instance_of String end it 'handles default value' do klass.enumerize(:foo, :in => [:a, :b], :default => :b) object.foo.must_equal 'b' end it 'handles default value with lambda' do klass.enumerize(:foo, :in => [:a, :b], :default => lambda { :b }) object.foo.must_equal 'b' end it 'injects object instance into lamda default value' do klass.enumerize(:foo, :in => [:a, :b], :default => lambda { |obj| :b if obj.is_a? klass }) object.foo.must_equal 'b' end it 'raises exception on invalid default value' do proc { klass.enumerize(:foo, :in => [:a, :b], :default => :c) }.must_raise ArgumentError end it 'has enumerized attributes' do klass.enumerized_attributes.must_be_empty klass.enumerize(:foo, :in => %w[a b]) klass.enumerized_attributes[:foo].must_be_instance_of Enumerize::Attribute end it "doesn't override existing method" do method = klass.method(:name) klass.enumerize(:name, :in => %w[a b], :default => 'a') klass.method(:name).must_equal method end it "inherits enumerized attributes from a parent class" do klass.enumerize(:foo, :in => %w[a b]) subklass.enumerized_attributes[:foo].must_be_instance_of Enumerize::Attribute end it "inherits enumerized attributes from a grandparent class" do klass.enumerize(:foo, :in => %w[a b]) Class.new(subklass).enumerized_attributes[:foo].must_be_instance_of Enumerize::Attribute end it "doesn't add enumerized attributes to parent class" do klass.enumerize(:foo, :in => %w[a b]) subklass.enumerize(:bar, :in => %w[c d]) klass.enumerized_attributes[:bar].must_equal nil end it 'adds new parent class attributes to subclass' do subklass = Class.new(klass) klass.enumerize :foo, :in => %w[a b] subklass.enumerized_attributes[:foo].must_be_instance_of Enumerize::Attribute end it 'stores nil value' do klass.enumerize(:foo, :in => [:a, :b]) object.foo = nil object.instance_variable_get(:@foo).must_equal nil end it 'casts value to string for validation' do klass.enumerize(:foo, :in => [:a, :b]) object.foo = :c object.read_attribute_for_validation(:foo).must_equal 'c' end it "doesn't cast nil to string for validation" do klass.enumerize(:foo, :in => [:a, :b]) object.foo = nil object.read_attribute_for_validation(:foo).must_equal nil end it 'calls super in the accessor method' do accessors = Module.new do def attributes @attributes ||= {} end def foo attributes[:foo] end def foo=(v) attributes[:foo] = v end end klass = Class.new do include accessors extend Enumerize enumerize :foo, :in => %w[test] end object = klass.new object.foo.must_be_nil object.attributes.must_equal({:foo => nil}) object.foo = 'test' object.foo.must_equal 'test' object.attributes.must_equal(:foo => 'test') end it 'stores hash values' do klass.enumerize(:foo, :in => {:a => 1, :b => 2}) object.foo = :a object.instance_variable_get(:@foo).must_equal 1 object.foo.must_equal 'a' object.foo = :b object.instance_variable_get(:@foo).must_equal 2 object.foo.must_equal 'b' end it 'returns custom value' do klass.enumerize(:foo, :in => {:a => 1, :b => 2}) object.foo = :a object.foo_value.must_equal 1 object.foo = :b object.foo_value.must_equal 2 end end enumerize-1.0.0/test/activerecord_test.rb0000644000004100000410000002145212560050170020560 0ustar www-datawww-datarequire 'test_helper' require 'active_record' require 'logger' silence_warnings do ActiveRecord::Migration.verbose = false ActiveRecord::Base.logger = Logger.new(nil) ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:") end ActiveRecord::Base.connection.instance_eval do create_table :users do |t| t.string :sex t.string :role t.string :lambda_role t.string :name t.string :interests t.integer :status t.string :account_type, :default => :basic end create_table :documents do |t| t.string :visibility t.timestamps null: true end end class BaseEntity < ActiveRecord::Base self.abstract_class = true extend Enumerize enumerize :visibility, :in => [:public, :private, :protected], :scope => true, :default => :public end class Document < BaseEntity end module RoleEnum extend Enumerize enumerize :role, :in => [:user, :admin], :default => :user, scope: :having_role enumerize :lambda_role, :in => [:user, :admin], :default => lambda { :admin } end class User < ActiveRecord::Base extend Enumerize include RoleEnum enumerize :sex, :in => [:male, :female] serialize :interests, Array enumerize :interests, :in => [:music, :sports, :dancing, :programming], :multiple => true enumerize :status, :in => { active: 1, blocked: 2 }, scope: true enumerize :account_type, :in => [:basic, :premium] end class UniqStatusUser < User validates :status, uniqueness: true validates :sex, presence: true end describe Enumerize::ActiveRecordSupport do it 'sets nil if invalid value is passed' do user = User.new user.sex = :invalid user.sex.must_equal nil end it 'saves value' do User.delete_all user = User.new user.sex = :female user.save! user.sex.must_equal 'female' end it 'loads value' do User.delete_all User.create!(:sex => :male) store_translations(:en, :enumerize => {:sex => {:male => 'Male'}}) do user = User.first user.sex.must_equal 'male' user.sex_text.must_equal 'Male' end end it 'has default value' do User.new.role.must_equal 'user' User.new.attributes['role'].must_equal 'user' end it 'does not set default value for not selected attributes' do User.delete_all User.create!(:sex => :male) assert_equal ['id'], User.select(:id).first.attributes.keys end it 'has default value with lambda' do User.new.lambda_role.must_equal 'admin' User.new.attributes['lambda_role'].must_equal 'admin' end it 'uses after_initialize callback to set default value' do User.delete_all User.create!(sex: 'male', lambda_role: nil) user = User.where(:sex => 'male').first user.lambda_role.must_equal 'admin' end it 'uses default value from db column' do User.new.account_type.must_equal 'basic' end it 'has default value with default scope' do UserWithDefaultScope = Class.new(User) do default_scope -> { having_role(:user) } end UserWithDefaultScope.new.role.must_equal 'user' UserWithDefaultScope.new.attributes['role'].must_equal 'user' end it 'validates inclusion' do user = User.new user.role = 'wrong' user.wont_be :valid? user.errors[:role].must_include 'is not included in the list' end it 'validates inclusion when using write_attribute with string attribute' do user = User.new user.send(:write_attribute, 'role', 'wrong') user.read_attribute_for_validation(:role).must_equal 'wrong' user.wont_be :valid? user.errors[:role].must_include 'is not included in the list' end it 'validates inclusion when using write_attribute with symbol attribute' do user = User.new user.send(:write_attribute, :role, 'wrong') user.read_attribute_for_validation(:role).must_equal 'wrong' user.wont_be :valid? user.errors[:role].must_include 'is not included in the list' end it 'validates inclusion on mass assignment' do assert_raises ActiveRecord::RecordInvalid do User.create!(role: 'wrong') end end it "uses persisted value for validation if it hasn't been set" do user = User.create! :sex => :male User.find(user.id).read_attribute_for_validation(:sex).must_equal 'male' end it 'is valid with empty string assigned' do user = User.new user.role = '' user.must_be :valid? end it 'stores nil when empty string assigned' do user = User.new user.role = '' user.read_attribute(:role).must_equal nil end it 'supports multiple attributes' do user = User.new user.interests.must_be_empty user.interests << :music user.interests.must_equal %w(music) user.save! user = User.find(user.id) user.interests.must_be_instance_of Enumerize::Set user.interests.must_equal %w(music) user.interests << :sports user.interests.must_equal %w(music sports) user.interests = [] interests = user.interests interests << :music interests.must_equal %w(music) interests << :dancing interests.must_equal %w(music dancing) end it 'stores multiple value passed passed to new' do user = User.new(interests: [:music, :dancing]) user.save! user.interests.must_equal %w(music dancing) User.find(user.id).interests.must_equal %w(music dancing) end it 'returns invalid multiple value for validation' do user = User.new user.interests << :music user.interests << :invalid values = user.read_attribute_for_validation(:interests) values.must_equal %w(music invalid) end it 'validates multiple attributes' do user = User.new user.interests << :invalid user.wont_be :valid? user.interests = Object.new user.wont_be :valid? user.interests = ['music', ''] user.must_be :valid? end it 'stores custom values for multiple attributes' do User.delete_all klass = Class.new(User) klass.enumerize :interests, in: { music: 0, sports: 1, dancing: 2, programming: 3}, multiple: true user = klass.new user.interests << :music user.read_attribute(:interests).must_equal [0] user.interests.must_equal %w(music) user.save user = klass.find(user.id) user.interests.must_equal %w(music) end it 'adds scope' do User.delete_all user_1 = User.create!(status: :active, role: :admin) user_2 = User.create!(status: :blocked) User.with_status(:active).must_equal [user_1] User.with_status(:blocked).must_equal [user_2] User.with_status(:active, :blocked).to_set.must_equal [user_1, user_2].to_set User.without_status(:active).must_equal [user_2] User.without_status(:active, :blocked).must_equal [] User.having_role(:admin).must_equal [user_1] end it 'ignores not enumerized values that passed to the scope method' do User.delete_all User.with_status(:foo).must_equal [] end it 'allows either key or value as valid' do user_1 = User.new(status: :active) user_2 = User.new(status: 1) user_3 = User.new(status: '1') user_1.status.must_equal 'active' user_2.status.must_equal 'active' user_3.status.must_equal 'active' user_1.must_be :valid? user_2.must_be :valid? user_3.must_be :valid? end it 'supports defining enumerized attributes on abstract class' do Document.delete_all document = Document.new document.visibility = :protected document.visibility.must_equal 'protected' end it 'supports defining enumerized scopes on abstract class' do Document.delete_all document_1 = Document.create!(visibility: :public) document_2 = Document.create!(visibility: :private) Document.with_visibility(:public).must_equal [document_1] end it 'validates uniqueness' do user = User.new user.status = :active user.save! user = UniqStatusUser.new user.status = :active user.valid? user.errors[:status].wont_be :empty? end it 'is valid after #becomes' do User.delete_all user = User.new user.sex = :male user.save! uniq_user = User.find(user.id).becomes(UniqStatusUser) uniq_user.valid? uniq_user.errors.must_be_empty end it 'supports multiple attributes in #becomes' do User.delete_all uniq_user = UniqStatusUser.new uniq_user.interests = [:sports, :dancing] uniq_user.sex = :male uniq_user.save! user = uniq_user.becomes(User) user.sex.must_equal uniq_user.sex user.interests.must_equal uniq_user.interests end it "doesn't update record" do Document.delete_all expected = Time.utc(2010, 10, 10) document = Document.new document.updated_at = expected document.save! document = Document.last document.save! assert_equal expected, document.updated_at end it 'changes from dirty should be serialized as scalar values' do user = User.create(:status => :active) user.status = :blocked assert_equal [1, 2], YAML.load(user.changes.to_yaml)[:status] end end enumerize-1.0.0/test/value_test.rb0000644000004100000410000000757012560050170017227 0ustar www-datawww-datarequire 'test_helper' require 'yaml' describe Enumerize::Value do let(:attr) { Struct.new(:values).new([]) } let(:value) { Enumerize::Value.new(attr, 'test_value', 1) } it 'is a string' do value.must_be_kind_of String end describe 'equality' do it 'is compared to string' do value.must_be :==, 'test_value' value.wont_be :==, 'not_value' end it 'is compared to symbol' do value.must_be :==, :test_value value.wont_be :==, :not_value end it 'is compared to integer' do value.must_be :==, 1 value.wont_be :==, 2 end end describe 'translation' do let(:attr) { Struct.new(:values, :name, :i18n_scopes).new([], "attribute_name", []) } it 'uses common translation' do store_translations(:en, :enumerize => {:attribute_name => {:test_value => "Common translation"}}) do value.text.must_be :==, "Common translation" end end it 'uses default translation from the "default" section if its present' do store_translations(:en, :enumerize => {:defaults => {:attribute_name => {:test_value => "Common translation"}}}) do value.text.must_be :==, "Common translation" end end it 'uses model specific translation' do attr.i18n_scopes = ["enumerize.model_name.attribute_name"] store_translations(:en, :enumerize => {:model_name => {:attribute_name => {:test_value => "Model Specific translation"}}}) do value.text.must_be :==, "Model Specific translation" end end it 'uses model specific translation rather than common translation' do attr.i18n_scopes = ["enumerize.model_name.attribute_name"] store_translations(:en, :enumerize => {:attribute_name => {:test_value => "Common translation"}, :model_name => {:attribute_name => {:test_value => "Model Specific translation"}}}) do value.text.must_be :==, "Model Specific translation" end end it 'uses simply humanized value when translation is undefined' do store_translations(:en, :enumerize => {}) do value.text.must_be :==, "Test value" end end it 'uses specified in options translation scope' do attr.i18n_scopes = ["other.scope"] store_translations(:en, :other => {:scope => {:test_value => "Scope specific translation"}}) do value.text.must_be :==, "Scope specific translation" end end it 'uses first found translation scope from options' do attr.i18n_scopes = ["nonexistent.scope", "other.scope"] store_translations(:en, :other => {:scope => {:test_value => "Scope specific translation"}}) do value.text.must_be :==, "Scope specific translation" end end end describe 'boolean methods comparison' do before do attr.values = [value, Enumerize::Value.new(attr, 'other_value')] end it 'returns true if value equals method' do value.test_value?.must_equal true end it 'returns false if value does not equal method' do value.other_value?.must_equal false end it 'raises NoMethodError if there are no values like boolean method' do proc { value.some_method? }.must_raise NoMethodError end it 'raises ArgumentError if arguments are passed' do proc { value.other_value?('<3') }.must_raise ArgumentError end it 'responds to methods for existing values' do value.must_respond_to :test_value? value.must_respond_to :other_value? end it 'returns a method object' do value.method(:test_value?).must_be_instance_of Method end it "doesn't respond to a method for not existing value" do value.wont_respond_to :some_method? end end describe 'serialization' do let(:value) { Enumerize::Value.new(attr, 'test_value') } it 'should be serialized to yaml as string value' do assert_equal YAML.dump('test_value'), YAML.dump(value) end end end enumerize-1.0.0/test/multiple_test.rb0000644000004100000410000000262712560050170017744 0ustar www-datawww-datarequire 'test_helper' describe Enumerize::Base do let(:klass) do Class.new do extend Enumerize end end let(:subklass) do Class.new(klass) end let(:object) { klass.new } it 'returns [] when not set' do klass.enumerize :foos, in: %w(a b), multiple: true object.foos.must_equal [] end it 'returns setted array' do klass.enumerize :foos, in: %w(a b c), multiple: true object.foos = %w(a c) object.foos.must_equal %w(a c) end it 'sets default value as single value' do klass.enumerize :foos, in: %w(a b c), default: 'b', multiple: true object.foos.must_equal %w(b) end it 'sets default value as array of one element' do klass.enumerize :foos, in: %w(a b c), default: %w(b), multiple: true object.foos.must_equal %w(b) end it 'sets default value as array of several elements' do klass.enumerize :foos, in: %w(a b c), default: %w(b c), multiple: true object.foos.must_equal %w(b c) end it "doesn't define _text method" do klass.enumerize :foos, in: %w(a b c), multiple: true object.wont_respond_to :foos_text end it "doesn't define _value method" do klass.enumerize :foos, in: %w(a b c), multiple: true object.wont_respond_to :foos_value end it "cannot define multiple with scope" do assert_raises ArgumentError do klass.enumerize :foos, in: %w(a b c), multiple: true, scope: true end end end enumerize-1.0.0/test/support/0000755000004100000410000000000012560050170016232 5ustar www-datawww-dataenumerize-1.0.0/test/support/view_test_helper.rb0000644000004100000410000000126612560050170022134 0ustar www-datawww-datarequire 'active_support/concern' require 'active_support/testing/setup_and_teardown' if defined?(ActionView::RoutingUrlFor) ActionView::RoutingUrlFor.send(:include, ActionDispatch::Routing::UrlFor) end module ViewTestHelper extend ActiveSupport::Concern include ActiveSupport::Testing::SetupAndTeardown include ActionView::TestCase::Behavior included do setup :set_controller end def set_controller @controller = MockController.new end def method_missing(method, *args) super unless method.to_s =~ /_path$/ end def respond_to?(method, include_private=false) method.to_s =~ /_path$/ || super end def protect_against_forgery? false end end enumerize-1.0.0/test/support/mock_controller.rb0000644000004100000410000000047012560050170021754 0ustar www-datawww-dataclass MockController attr_writer :action_name def _routes self end def action_name defined?(@action_name) ? @action_name : "edit" end def url_for(*args) "http://example.com" end def url_helpers self end def url_options {} end def hash_for_users_path(*); end end enumerize-1.0.0/test/attribute_test.rb0000644000004100000410000000743612560050170020117 0ustar www-datawww-datarequire 'test_helper' describe Enumerize::Attribute do def attr @attr ||= nil end def build_attr(*args, &block) @attr = Enumerize::Attribute.new(*args, &block) end it 'returns values' do build_attr nil, :foo, :in => [:a, :b] attr.values.must_equal %w[a b] end it 'converts name to symbol' do build_attr nil, 'foo', :in => %w[a b] attr.name.must_equal :foo end it 'uses custom value class' do value_class = Class.new(Enumerize::Value) build_attr nil, 'foo', :in => %w[a b], :value_class => value_class attr.values.first.must_be_instance_of value_class end describe 'i18n scopes' do it 'returns scopes from options' do build_attr nil, 'foo', :in => %w[a b], :i18n_scope => %w[bar buzz] attr.i18n_scopes.must_equal %w[bar buzz] end it 'accepts only string scopes' do proc { build_attr nil, 'foo', :in => %w[a b], :i18n_scope => [%w[bar buzz], "bar.buzz"] }.must_raise ArgumentError end end describe 'options for select' do it 'returns all options for select' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do build_attr nil, :foo, :in => %w[a b] attr.options.must_equal [['a text', 'a'], ['b text', 'b']] end end it 'returns requested options for select via :only' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do build_attr nil, :foo, :in => %w[a b] attr.options(:only => :a).must_equal [['a text', 'a']] attr.options(:only => [:b]).must_equal [['b text', 'b']] attr.options(:only => []).must_equal [] end end it 'returns requested options for select via :except' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do build_attr nil, :foo, :in => %w[a b] attr.options(:except => :a).must_equal [['b text', 'b']] attr.options(:except => :b).must_equal [['a text', 'a']] attr.options(:except => []).must_equal [['a text', 'a'], ['b text', 'b']] end end it 'does not work with both :only and :except' do store_translations(:en, :enumerize => {:foo => {:a => 'a text', :b => 'b text'}}) do build_attr nil, :foo, :in => %w[a b] proc { attr.options(:except => [], :only => []) }.must_raise ArgumentError end end end describe 'values hash' do before do build_attr nil, :foo, :in => {:a => 1, :b => 2} end it 'returns hash keys as values' do attr.values.must_equal %w[a b] end it 'finds values by hash values' do attr.find_value(1).must_equal 'a' attr.find_value(2).must_equal 'b' end end it 'sets up shortcut methods for each value' do build_attr nil, :foo, :in => {:a => 1, :b => 2} attr.must_respond_to :a attr.must_respond_to :b attr.a.value.must_equal 1 attr.b.value.must_equal 2 attr.a.text.must_equal 'A' attr.b.text.must_equal 'B' end describe 'values hash with zero' do before do build_attr nil, :foo, :in => {:a => 1, :b => 2, :c => 0} end it 'returns hash keys as values' do attr.values.must_equal %w[a b c] end it 'finds values by hash values' do attr.find_value(1).must_equal 'a' attr.find_value(2).must_equal 'b' attr.find_value(0).must_equal 'c' end it 'finds all values by hash values' do attr.find_values(1, 2, 0).must_equal ['a', 'b', 'c'] end end describe 'boolean values hash' do before do build_attr nil, :foo, :in => {:a => true, :b => false} end it 'returns hash keys as values' do attr.values.must_equal %w[a b] end it 'finds values by hash values' do attr.find_value(true).must_equal 'a' attr.find_value(false).must_equal 'b' end end end enumerize-1.0.0/.gitignore0000644000004100000410000000035212560050170015527 0ustar www-datawww-data*.gem *.rbc .bundle .config .ruby-version .yardoc .idea/ enumerize.iml Gemfile*.lock gemfiles/Gemfile-*.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man log/* pkg rdoc spec/reports test/tmp test/version_tmp tmp vendor/bundle enumerize-1.0.0/Gemfile.mongo_mapper0000644000004100000410000000066512560050170017523 0ustar www-datawww-datasource 'https://rubygems.org' gemspec gem 'rake' gem 'minitest', '~> 5.5.1' gem 'rspec', :require => false gem 'rails', '4.2.0', :require => false gem 'sqlite3', :platform => [:ruby, :mswin, :mingw] gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby platforms :rbx do gem 'rubysl', '~> 2.0' gem 'psych' gem 'rubinius-developer_tools' gem 'rubysl-test-unit' end gem 'mongo_mapper' gem 'simple_form' gem 'formtastic' enumerize-1.0.0/CHANGELOG.md0000644000004100000410000002076112560050170015356 0ustar www-datawww-data## master ### enhancements ### bug fix ## 1.0.0 (August 2, 2015) ### enhancements * Add `texts` method for getting an array of text values of the enumerized field with multiple type. (by [@huynhquancam](https://github.com/huynhquancam)) * Drop Rails 3.2 support. (by [@nashby](https://github.com/nashby)) ### bug fix * Fix conflicts when Active Record and Mongoid are used at the same time. (by [@matsu911](https://github.com/matsu911)) ## 0.11.0 (March 29, 2015) ## ### enhancements * Add ability to set default value for enumerized field with multiple type. (by [@nashby](https://github.com/nashby)) * Support Rails 4.2. (by [@lest](https://github.com/lest)) ### bug fix * Use Mongoid's `:in` method for generated scopes, fix chained scopes. (by [@nashby](https://github.com/nashby)) * Use `after_initialize` callback to set default value in Mongoid documents. (by [@nashby](https://github.com/nashby)) ## 0.10.1 (March 4, 2015) ## ### bug fix * Use method_missing instead of defining singleton class methods to allow Marshal serialization (by [@lest](https://github.com/lest)) ## 0.10.0 (February 17, 2015) ## ### enhancements * Add scopes support to mongoid documents (by [@nashby](https://github.com/nashby)) * Use underscore.humanize in #text to make use of Inflector acronyms (by [@mintuhouse](https://github.com/mintuhouse)) * Raise an exception when :scope option is used together with :multiple option (by [@maurogeorge](https://github.com/maurogeorge)) * Use alias_method_chain instead of overriding Class#inherited (by [@yuroyoro](https://github.com/yuroyoro)) * Shortcut methods to retrieve enumerize values (by [@CyborgMaster](https://github.com/CyborgMaster)) * Extend equality operator to support comparing with symbols and custom values (e.g. integers) (by [@CyborgMaster](https://github.com/CyborgMaster)) ## 0.9.0 (December 11, 2014) ## ### enhancements * Add :value_class option (by [@lest](https://github.com/lest)) * Use 'defaults' scope in the localization file for the attributes that used across several models. This will help to avoid conflicting keys with model names and attribute names. Example: ```yml en: enumerize: defaults: sex: male: Male female: Female ``` You still can use the old solution without "default" scope: ```yml en: enumerize: sex: male: Male female: Female ``` (by [@nashby](https://github.com/nashby)) ### bug fix * Store values for validation using string keys (by [@nagyt234](https://github.com/nagyt234)) * Store custom values for multiple attributes (by [@lest](https://github.com/lest)) * Support validations after using AR#becomes (by [@lest](https://github.com/lest)) * Do not try to set attribute for not selected attributes (by [@dany1468](https://github.com/dany1468)) ## 0.8.0 (March 4, 2014) ## ### enhancements * Integration with SimpleForm's `input_field` (by [@nashby](https://github.com/nashby)) * Support multiple attributes in Active Record #becomes method (by [@lest](https://github.com/lest)) * Add ability to specify localization scope with `i18n_scope` option (by [@dreamfall](https://github.com/dreamfall)) ### bug fix * Fix Rails Admin integration when custom values are used (by [@brenes](https://github.com/brenes)) * Fix RSpec integration using enumerize with Spring (by [@winston](https://github.com/winston)) * Return proper RSpec failure message for enumerized attribute with default value (by [@nashby](https://github.com/nashby)) * Return proper RSpec description for enumerized attribute without default value (by [@andreygerasimchuk](https://github.com/andreygerasimchuk)) * Do not try to set default value for not selected attributes (by [@nashby](https://github.com/nashby)) * Fix uniqueness validation with Active Record (by [@lest](https://github.com/lest)) * Fix loading of attributes with multiple: true in mongoid (by [glebtv](https://github.com/glebtv)) * Serialize value as scalar type (by [@ka8725](https://github.com/ka8725)) ## 0.7.0 (August 21, 2013) ## ### enhancements * Give priority to model specific translation definition. See example [here](https://github.com/brainspec/enumerize/pull/96) (by [@labocho](https://github.com/labocho)) * Allow lambda in default value (by [@adie](https://github.com/adie)) * Add predicate methods to the multiple attributes (by [@nashby](https://github.com/nashby)) * Add RSpec matcher (by [@nashby](https://github.com/nashby)) * Add `*_value` method that returns actual value of the enumerized attribute (useful for attributes with custom values) (by [@tkyowa](https://github.com/tkyowa)) ### bug fix * Make validation work when `write_attribute` is using for setting enumerized values (by [@nashby](https://github.com/nashby)) * Validates enumerized values when enumeration is included via module (by [@nashby](https://github.com/nashby)) and (by [@lest](https://github.com/lest)) ## 0.6.1 (May 20, 2013) ## ### bug fix * Don't raise error when enumerized attribute is already defined. (by [@lest](https://github.com/lest)) ## 0.6.0 (May 16, 2013) ## ### enhancements * Use inclusion error message for invalid values (by [@lest](https://github.com/lest)) * Add `:only` and `except` options to the `Attribute#options` method. (by [@thehappycoder](https://github.com/thehappycoder) and [@randoum](https://github.com/randoum)) * ActiveRecord scopes. (by [@lest](https://github.com/lest), [@banyan](https://github.com/banyan) and [@nashby](https://github.com/nashby)) * Support for RailsAdmin (by [@drewda](https://github.com/drewda)) ### bug fix * Return correct default value for enumerized attribute using `default_scope` with generated scope [@nashby](https://github.com/nashby) * Allow either key or value as valid (by [aghull](https://github.com/aghull) and [@lest](https://github.com/lest)) * Use default enum value from db column (by [@lest](https://github.com/lest)) ## 0.5.1 (December 10, 2012) ## ### bug fix * Always return Enumerize::Set for multiple attributes (by [@nashby](https://github.com/nashby)) ## 0.5.0 (October 31, 2012) ## The previous method of adding enumerize to a class was deprecated. Please use `extend Enumerize` instead of `include Enumerize`. ### enhancements * SimpleForm support for multiple attributes. (by [@nashby](https://github.com/nashby)) * Formtastic support for multiple attributes. (by [@nashby](https://github.com/nashby)) * Array-like multiple attributes. (by [@lest](https://github.com/lest)) ## 0.4.0 (September 6, 2012) ## Legacy support was dropped. The following versions are supported: * Ruby 1.9.3+ (including JRuby and Rubinius) * Rails 3.2+ * Formtastic 2.2+ * SimpleForm 2+ * Mongoid 3+ ### enhancements * Ability to define predicate methods on enumerized object. (by [@lest](https://github.com/lest)) ## 0.3.0 (July 9, 2012) ## ### enhancements * Accept a values hash to store an attribute using custom values (e.g. integers) (by [@lest](https://github.com/lest)) ## 0.2.2 (May 22, 2012) ## ### bug fix * Correctly assign default value to handle mass assignment in Active Record (by [@lest](https://github.com/lest)) ## 0.2.1 (May 21, 2012) ## ### bug fix * Call super in attribute accessors if available (by [@lest](https://github.com/lest)) ## 0.2.0 (March 29, 2012) ## ### enhancements * Ability to enumerize attributes in a module and then include it into classes (by [@lest](https://github.com/lest)) * Add error to a model when attribute value is not included in allowed list (by [@lest](https://github.com/lest)) ### bug fix * Inheriting enumerized attributes (by [@cgunther](https://github.com/cgunther) and [@nashby](https://github.com/nashby)) * Don't cast nil to string (by [@jimryan](https://github.com/jimryan)) ## 0.1.1 (March 6, 2012) ## ### bug fix * I18n regression: Multiple calls to value #text return different results (by [@cgunther](https://github.com/cgunther) and [@lest](https://github.com/lest)) ## 0.1.0 (March 5, 2012) ## ### enhancements * Return humanized value if there are no translations (by [@nashby](https://github.com/nashby)) * Integration with SimpleForm (by [@nashby](https://github.com/nashby)) * Integration with Formtastic (by [@lest](https://github.com/lest)) ## 0.0.4 (February 8, 2012) ## ### bug fix * Make attribute accessors to work with ActiveRecord 3.1.x (by [@lest](https://github.com/lest)) ## 0.0.3 (February 8, 2012) ## ### enhancements * Mongoid support (by [@lest](https://github.com/lest)) * Boolean methods (by [@Dreamfa11](https://github.com/Dreamfa11)) enumerize-1.0.0/README.md0000644000004100000410000001567712560050170015036 0ustar www-datawww-data# Enumerize [![TravisCI](https://secure.travis-ci.org/brainspec/enumerize.png?branch=master)](http://travis-ci.org/brainspec/enumerize) [![Gemnasium](https://gemnasium.com/brainspec/enumerize.png)](https://gemnasium.com/brainspec/enumerize) Enumerated attributes with I18n and ActiveRecord/Mongoid/MongoMapper support ## Installation Add this line to your application's Gemfile: gem 'enumerize' And then execute: $ bundle Or install it yourself as: $ gem install enumerize ## Usage Basic: ```ruby class User extend Enumerize enumerize :sex, in: [:male, :female] end ``` Note that enumerized values are just identificators so if you want to use multi-word, etc. values you should use `I18n` feature. ActiveRecord: ```ruby class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :sex t.string :role t.timestamps end end end class User < ActiveRecord::Base extend Enumerize enumerize :sex, in: [:male, :female], default: lambda { |user| SexIdentifier.sex_for_name(user.name).to_sym } enumerize :role, in: [:user, :admin], default: :user end ``` Mongoid: ```ruby class User include Mongoid::Document extend Enumerize field :role enumerize :role, in: [:user, :admin], default: :user end ``` MongoMapper: ```ruby class User include MongoMapper::Document extend Enumerize key :role enumerize :role, in: [:user, :admin], default: :user end ``` I18n: ```ruby en: enumerize: user: sex: male: "Male" female: "Female" ``` or if you use `sex` attribute across several models you can use `defaults` scope: ```ruby en: enumerize: defaults: sex: male: "Male" female: "Female" ``` You can also pass `i18n_scope` option to specify scope (or array of scopes) storring the translations. Note that `i18n_scope` option does not accept scope as array: ```ruby class Person extend Enumerize extend ActiveModel::Naming enumerize :sex, in: %w[male female], i18n_scope: "sex" enumerize :color, in: %w[black white], i18n_scope: ["various.colors", "colors"] end # localization file en: sex: male: "Male" female: "Female" various: colors: black: "Black" colors: white: "White" ``` Note that if you want to use I18n feature with plain Ruby object don't forget to extend it with `ActiveModel::Naming`: ```ruby class User extend Enumerize extend ActiveModel::Naming end ``` get attribute value: ```ruby @user.sex_text # or @user.sex.text ``` get all values for enumerized attribute: ```ruby User.sex.values # or User.enumerized_attributes[:sex].values ``` use it with forms (it supports `:only` and `:except` options): ```erb <%= form_for @user do |f| %> <%= f.select :sex, User.sex.options %> <% end %> ``` Boolean methods: ```ruby user.sex = :male user.sex.male? #=> true user.sex.female? #=> false ``` Predicate methods: ```ruby class User extend Enumerize enumerize :sex, in: %w(male female), predicates: true end user = User.new user.male? # => false user.female? # => false user.sex = 'male' user.male? # => true user.female? # => false ``` Using prefix: ```ruby class User extend Enumerize enumerize :sex, in: %w(male female), predicates: { prefix: true } end user = User.new user.sex = 'female' user.sex_female? # => true ``` Use `:only` and `:except` options to specify what values create predicate methods for. To make some attributes shared across different classes it's possible to define them in a separate module and then include it into classes: ```ruby module PersonEnumerations extend Enumerize enumerize :sex, in: %w[male female] end class Person include PersonEnumerations end class User include PersonEnumerations end ``` It's also possible to store enumerized attribute value using custom values (e.g. integers). You can pass a hash as `:in` option to achieve this: ```ruby class User < ActiveRecord::Base extend Enumerize enumerize :role, in: {:user => 1, :admin => 2} end user = User.new user.role = :user user.role #=> 'user' user.role_value #=> 1 User.role.find_value(:user).value #=> 1 User.role.find_value(:admin).value #=> 2 ``` ActiveRecord scopes: ```ruby class User < ActiveRecord::Base extend Enumerize enumerize :sex, :in => [:male, :female], scope: true enumerize :status, :in => { active: 1, blocked: 2 }, scope: :having_status end User.with_sex(:female) # SELECT "users".* FROM "users" WHERE "users"."sex" IN ('female') User.without_sex(:male) # SELECT "users".* FROM "users" WHERE "users"."sex" NOT IN ('male') User.having_status(:blocked).with_sex(:male, :female) # SELECT "users".* FROM "users" WHERE "users"."status" IN (2) AND "users"."sex" IN ('male', 'female') ``` :warning: It is not possible to define a scope when using the `:multiple` option. :warning: Array-like attributes with plain ruby objects: ```ruby class User extend Enumerize enumerize :interests, in: [:music, :sports], multiple: true end user = User.new user.interests << :music user.interests << :sports ``` and with ActiveRecord: ```ruby class User < ActiveRecord::Base extend Enumerize serialize :interests, Array enumerize :interests, in: [:music, :sports], multiple: true end ``` ### SimpleForm If you are using SimpleForm gem you don't need to specify input type (`:select` by default) and collection: ```erb <%= simple_form_for @user do |f| %> <%= f.input :sex %> <% end %> ``` and if you want it as radio buttons: ```erb <%= simple_form_for @user do |f| %> <%= f.input :sex, :as => :radio_buttons %> <% end %> ``` ### Formtastic If you are using Formtastic gem you also don't need to specify input type (`:select` by default) and collection: ```erb <%= semantic_form_for @user do |f| %> <%= f.input :sex %> <% end %> ``` and if you want it as radio buttons: ```erb <%= semantic_form_for @user do |f| %> <%= f.input :sex, :as => :radio %> <% end %> ``` ### RSpec Also you can use builtin RSpec matcher: ```ruby class User extend Enumerize enumerize :sex, in: [:male, :female], default: :male end describe User do it { should enumerize(:sex).in(:male, :female) } it { should enumerize(:sex).in(:male, :female).with_default(:male) } # or with RSpec 3 expect syntax it { is_expected.to enumerize(:sex).in(:male, :female) } end ``` ### Minitest with Shoulda You can use the RSpec matcher with shoulda in your tests by adding two lines in your `test_helper.rb` inside `class ActiveSupport::TestCase` definition: ```ruby class ActiveSupport::TestCase ActiveRecord::Migration.check_pending! require 'enumerize/integrations/rspec' extend Enumerize::Integrations::RSpec ... end ``` ### Other Integrations Enumerize integrates with the following automatically: * [RailsAdmin](https://github.com/sferik/rails_admin/) ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Added some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request