attribute-filters 1.3.2 → 1.4.0
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.tar.gz.sig +0 -0
 - data/ChangeLog +388 -0
 - data/Gemfile.lock +14 -14
 - data/Manifest.txt +8 -0
 - data/README.md +45 -31
 - data/attribute-filters.gemspec +3 -3
 - data/docs/HISTORY +63 -27
 - data/docs/TODO +17 -2
 - data/docs/USAGE.md +1161 -76
 - data/lib/attribute-filters.rb +4 -0
 - data/lib/attribute-filters/attribute_set.rb +92 -1
 - data/lib/attribute-filters/attribute_set_annotations.rb +259 -0
 - data/lib/attribute-filters/attribute_set_attrquery.rb +9 -8
 - data/lib/attribute-filters/attribute_set_enum.rb +76 -45
 - data/lib/attribute-filters/attribute_set_query.rb +65 -7
 - data/lib/attribute-filters/backports.rb +37 -0
 - data/lib/attribute-filters/common_filters.rb +46 -128
 - data/lib/attribute-filters/common_filters/case.rb +159 -0
 - data/lib/attribute-filters/common_filters/join.rb +98 -0
 - data/lib/attribute-filters/common_filters/split.rb +130 -0
 - data/lib/attribute-filters/common_filters/squeeze.rb +75 -0
 - data/lib/attribute-filters/common_filters/strip.rb +46 -0
 - data/lib/attribute-filters/dsl_attr_virtual.rb +50 -0
 - data/lib/attribute-filters/dsl_filters.rb +40 -29
 - data/lib/attribute-filters/dsl_sets.rb +122 -32
 - data/lib/attribute-filters/helpers.rb +14 -0
 - data/lib/attribute-filters/version.rb +1 -1
 - data/spec/attribute-filters_spec.rb +334 -13
 - data/spec/spec_helper.rb +9 -20
 - metadata +37 -29
 - metadata.gz.sig +0 -0
 
| 
         @@ -22,18 +22,29 @@ module ActiveModel 
     | 
|
| 
       22 
22 
     | 
    
         
             
                # Returns the attribute set of the given name or the set containing
         
     | 
| 
       23 
23 
     | 
    
         
             
                # all attributes (if the argument is not given).
         
     | 
| 
       24 
24 
     | 
    
         
             
                # 
         
     | 
| 
      
 25 
     | 
    
         
            +
                # If the given +set_name+ is a kind of String or Symbol then the method
         
     | 
| 
      
 26 
     | 
    
         
            +
                # returns a copy of a set that is stored within a model class. The copy
         
     | 
| 
      
 27 
     | 
    
         
            +
                # is wrapped in a `AttributeSet::AttrQuery` instance.
         
     | 
| 
      
 28 
     | 
    
         
            +
                # 
         
     | 
| 
      
 29 
     | 
    
         
            +
                # If the argument is a kind of {AttributeSet} then the local set
         
     | 
| 
      
 30 
     | 
    
         
            +
                # is taken and wrapped in a {AttributeSet::AttrQuery} instance.
         
     | 
| 
      
 31 
     | 
    
         
            +
                # 
         
     | 
| 
      
 32 
     | 
    
         
            +
                # If the argument is other kind than the specified above then
         
     | 
| 
      
 33 
     | 
    
         
            +
                # the method tries to initialize new, local set object and wraps
         
     | 
| 
      
 34 
     | 
    
         
            +
                # it in a `AttributeSet::AttrQuery` instance.
         
     | 
| 
      
 35 
     | 
    
         
            +
                # 
         
     | 
| 
       25 
36 
     | 
    
         
             
                # @note The returned value is a duplicate. Adding or removing
         
     | 
| 
       26 
     | 
    
         
            -
                #  elements to it will have no effect 
     | 
| 
       27 
     | 
    
         
            -
                #  is possible on a class-level only, since attribute sets
         
     | 
| 
      
 37 
     | 
    
         
            +
                #  elements to it will have no effect on class-level set.
         
     | 
| 
      
 38 
     | 
    
         
            +
                #  Altering attribute sets is possible on a class-level only, since attribute sets
         
     | 
| 
       28 
39 
     | 
    
         
             
                #  are part of models' interfaces.
         
     | 
| 
       29 
40 
     | 
    
         
             
                # 
         
     | 
| 
       30 
     | 
    
         
            -
                # @param set_name [Symbol] name of attribute set
         
     | 
| 
      
 41 
     | 
    
         
            +
                # @param set_name [Symbol] name of attribute set, attribute object or any object that can initialize a set
         
     | 
| 
       31 
42 
     | 
    
         
             
                # @return [AttributeSet] attribute set
         
     | 
| 
       32 
43 
     | 
    
         
             
                def attribute_set(set_name=nil)
         
     | 
| 
       33 
44 
     | 
    
         
             
                  if set_name.nil?
         
     | 
| 
       34 
45 
     | 
    
         
             
                    all_attributes
         
     | 
| 
       35 
46 
     | 
    
         
             
                  else
         
     | 
| 
       36 
     | 
    
         
            -
                    ActiveModel::AttributeSet::Query.new( 
     | 
| 
      
 47 
     | 
    
         
            +
                    ActiveModel::AttributeSet::Query.new(set_name, self)
         
     | 
| 
       37 
48 
     | 
    
         
             
                  end
         
     | 
| 
       38 
49 
     | 
    
         
             
                end
         
     | 
| 
       39 
50 
     | 
    
         
             
                alias_method :attributes_that_are,        :attribute_set
         
     | 
| 
         @@ -49,42 +60,83 @@ module ActiveModel 
     | 
|
| 
       49 
60 
     | 
    
         
             
                alias_method :attributes_set,             :attribute_set
         
     | 
| 
       50 
61 
     | 
    
         
             
                alias_method :properties_that,            :attribute_set
         
     | 
| 
       51 
62 
     | 
    
         | 
| 
       52 
     | 
    
         
            -
                # Returns  
     | 
| 
      
 63 
     | 
    
         
            +
                # Returns the attribute set of the given name without wrapping
         
     | 
| 
      
 64 
     | 
    
         
            +
                # the result in proxy methods.
         
     | 
| 
      
 65 
     | 
    
         
            +
                # 
         
     | 
| 
      
 66 
     | 
    
         
            +
                # @note The returned value is a duplicate. Adding or removing
         
     | 
| 
      
 67 
     | 
    
         
            +
                #  elements to it will have no effect. Altering attribute sets
         
     | 
| 
      
 68 
     | 
    
         
            +
                #  is possible on a class-level only, since attribute sets
         
     | 
| 
      
 69 
     | 
    
         
            +
                #  are part of models' interfaces.
         
     | 
| 
      
 70 
     | 
    
         
            +
                # 
         
     | 
| 
      
 71 
     | 
    
         
            +
                # @param set_name [Symbol] name of attribute set
         
     | 
| 
      
 72 
     | 
    
         
            +
                # @return [AttributeSet] attribute set
         
     | 
| 
      
 73 
     | 
    
         
            +
                def attribute_set_simple(set_name)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  self.class.attribute_set(set_name).dup
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                # Returns a set containing all known attributes
         
     | 
| 
      
 78 
     | 
    
         
            +
                # without wrapping it in a proxy.
         
     | 
| 
      
 79 
     | 
    
         
            +
                # 
         
     | 
| 
      
 80 
     | 
    
         
            +
                # @return [AttributeSet] attribute set
         
     | 
| 
      
 81 
     | 
    
         
            +
                def all_attributes_simple(no_presence_check = true)
         
     | 
| 
      
 82 
     | 
    
         
            +
                  (ActiveModel::AttributeSet.new(attributes.keys) +
         
     | 
| 
      
 83 
     | 
    
         
            +
                  all_accessible_attributes(true) +
         
     | 
| 
      
 84 
     | 
    
         
            +
                  all_protected_attributes(true)  +
         
     | 
| 
      
 85 
     | 
    
         
            +
                  __vatrf(no_presence_check)).delete("")
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                # Returns a set containing all known attributes.
         
     | 
| 
      
 89 
     | 
    
         
            +
                # 
         
     | 
| 
       53 
90 
     | 
    
         
             
                # @return [AttributeSet] attribute set
         
     | 
| 
       54 
91 
     | 
    
         
             
                def all_attributes
         
     | 
| 
       55 
     | 
    
         
            -
                  ActiveModel::AttributeSet::Query.new( 
     | 
| 
      
 92 
     | 
    
         
            +
                  ActiveModel::AttributeSet::Query.new(all_attributes_simple, self)
         
     | 
| 
       56 
93 
     | 
    
         
             
                end
         
     | 
| 
       57 
94 
     | 
    
         
             
                alias_method :all_attributes_set, :all_attributes
         
     | 
| 
       58 
95 
     | 
    
         | 
| 
       59 
96 
     | 
    
         
             
                # Returns a set containing all accessible attributes.
         
     | 
| 
      
 97 
     | 
    
         
            +
                # 
         
     | 
| 
      
 98 
     | 
    
         
            +
                # @param simple [Boolean] optional parameter that disables
         
     | 
| 
      
 99 
     | 
    
         
            +
                #   wrapping a resulting set in a proxy (defaults to +false+)
         
     | 
| 
       60 
100 
     | 
    
         
             
                # @return [AttributeSet] attribute set
         
     | 
| 
       61 
     | 
    
         
            -
                def all_accessible_attributes
         
     | 
| 
       62 
     | 
    
         
            -
                   
     | 
| 
      
 101 
     | 
    
         
            +
                def all_accessible_attributes(simple = false)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  c = self.class.class_eval { respond_to?(:accessible_attributes) ? accessible_attributes : [] }
         
     | 
| 
      
 103 
     | 
    
         
            +
                  simple ? AttributeSet.new(c) : AttributeSet::Query.new(c)
         
     | 
| 
       63 
104 
     | 
    
         
             
                end
         
     | 
| 
       64 
105 
     | 
    
         
             
                alias_method :accessible_attributes_set, :all_accessible_attributes
         
     | 
| 
       65 
106 
     | 
    
         | 
| 
       66 
107 
     | 
    
         
             
                # Returns a set containing all protected attributes.
         
     | 
| 
      
 108 
     | 
    
         
            +
                # 
         
     | 
| 
      
 109 
     | 
    
         
            +
                # @param simple [Boolean] optional parameter that disables
         
     | 
| 
      
 110 
     | 
    
         
            +
                #   wrapping a resulting set in a proxy (defaults to +false+)
         
     | 
| 
       67 
111 
     | 
    
         
             
                # @return [AttributeSet] attribute set
         
     | 
| 
       68 
     | 
    
         
            -
                def all_protected_attributes
         
     | 
| 
       69 
     | 
    
         
            -
                   
     | 
| 
      
 112 
     | 
    
         
            +
                def all_protected_attributes(simple = false)
         
     | 
| 
      
 113 
     | 
    
         
            +
                  c = self.class.class_eval { respond_to?(:protected_attributes) ? protected_attributes : [] }
         
     | 
| 
      
 114 
     | 
    
         
            +
                  simple ? AttributeSet.new(c) : AttributeSet::Query.new(c)
         
     | 
| 
       70 
115 
     | 
    
         
             
                end
         
     | 
| 
       71 
116 
     | 
    
         
             
                alias_method :protected_attributes_set, :all_protected_attributes
         
     | 
| 
       72 
117 
     | 
    
         | 
| 
       73 
118 
     | 
    
         
             
                # Returns a set containing all attributes that are not accessible attributes.
         
     | 
| 
       74 
119 
     | 
    
         
             
                # @return [AttributeSet] attribute set
         
     | 
| 
       75 
120 
     | 
    
         
             
                def all_inaccessible_attributes
         
     | 
| 
       76 
     | 
    
         
            -
                  all_attributes -  
     | 
| 
      
 121 
     | 
    
         
            +
                  all_attributes - all_accessible_attributes(true)
         
     | 
| 
       77 
122 
     | 
    
         
             
                end
         
     | 
| 
       78 
123 
     | 
    
         
             
                alias_method :all_non_accessible_attributes,  :all_inaccessible_attributes
         
     | 
| 
       79 
124 
     | 
    
         
             
                alias_method :inaccessible_attributes_set,    :all_inaccessible_attributes
         
     | 
| 
       80 
125 
     | 
    
         | 
| 
       81 
126 
     | 
    
         
             
                # Gets all the defined attribute sets.
         
     | 
| 
      
 127 
     | 
    
         
            +
                # 
         
     | 
| 
       82 
128 
     | 
    
         
             
                # @note Use +key+ method explicitly to check if the given set exists. The hash returned by this method
         
     | 
| 
       83 
129 
     | 
    
         
             
                #  will always return {AttributeSet} object. If there is no such set defined then the returned,
         
     | 
| 
       84 
130 
     | 
    
         
             
                #  matching set will be empty.
         
     | 
| 
      
 131 
     | 
    
         
            +
                # 
         
     | 
| 
       85 
132 
     | 
    
         
             
                # @return [Hash{Symbol => AttributeSet<String>}] the collection of attribute sets indexed by their names
         
     | 
| 
       86 
133 
     | 
    
         
             
                def attribute_sets
         
     | 
| 
       87 
     | 
    
         
            -
                  self.class.attribute_sets
         
     | 
| 
      
 134 
     | 
    
         
            +
                  s = self.class.attribute_sets
         
     | 
| 
      
 135 
     | 
    
         
            +
                  s.merge!(s) do |set_name, set_object|
         
     | 
| 
      
 136 
     | 
    
         
            +
                    ActiveModel::AttributeSet::Query.new(set_object, self)
         
     | 
| 
      
 137 
     | 
    
         
            +
                  end
         
     | 
| 
      
 138 
     | 
    
         
            +
                  s.default = ActiveModel::AttributeSet::Query.new(ActiveModel::AttributeSet.new.freeze, self)
         
     | 
| 
      
 139 
     | 
    
         
            +
                  s
         
     | 
| 
       88 
140 
     | 
    
         
             
                end
         
     | 
| 
       89 
141 
     | 
    
         
             
                alias_method :attributes_sets, :attribute_sets
         
     | 
| 
       90 
142 
     | 
    
         
             
                alias_method :properties_sets, :attribute_sets
         
     | 
| 
         @@ -108,9 +160,11 @@ module ActiveModel 
     | 
|
| 
       108 
160 
     | 
    
         
             
                alias_method :are_the_attributes,   :filtered_attribute
         
     | 
| 
       109 
161 
     | 
    
         | 
| 
       110 
162 
     | 
    
         
             
                # Gets all the defined attribute set names hashed by attribute names.
         
     | 
| 
      
 163 
     | 
    
         
            +
                # 
         
     | 
| 
       111 
164 
     | 
    
         
             
                # @note Use +key+ method explicitly to check if the given attribute is assigned to any set. The hash
         
     | 
| 
       112 
165 
     | 
    
         
             
                #  returned by this method will always return {AttributeSet} object. If the attribute is not assigned
         
     | 
| 
       113 
166 
     | 
    
         
             
                #  to any set then the returned, matching set will be empty.
         
     | 
| 
      
 167 
     | 
    
         
            +
                # 
         
     | 
| 
       114 
168 
     | 
    
         
             
                # @return [Hash{String => AttributeSet<Symbol>}] the collection of attribute set names indexed by attribute names
         
     | 
| 
       115 
169 
     | 
    
         
             
                def attributes_to_sets
         
     | 
| 
       116 
170 
     | 
    
         
             
                  self.class.attributes_to_sets
         
     | 
| 
         @@ -121,13 +175,13 @@ module ActiveModel 
     | 
|
| 
       121 
175 
     | 
    
         
             
                # that create DSL for managing attribute sets.
         
     | 
| 
       122 
176 
     | 
    
         
             
                module ClassMethods
         
     | 
| 
       123 
177 
     | 
    
         
             
                  # @overload attribute_set()
         
     | 
| 
       124 
     | 
    
         
            -
                  #   Gets all the defined attribute sets 
     | 
| 
      
 178 
     | 
    
         
            +
                  #   Gets all the defined attribute sets by calling +attribute_sets+.
         
     | 
| 
       125 
179 
     | 
    
         
             
                  #   @return [Hash{Symbol => AttributeSet<String>}] the collection of attribute sets indexed by their names
         
     | 
| 
       126 
180 
     | 
    
         
             
                  # 
         
     | 
| 
       127 
181 
     | 
    
         
             
                  # @overload attribute_set(set_name)
         
     | 
| 
       128 
     | 
    
         
            -
                  #   Gets the  
     | 
| 
      
 182 
     | 
    
         
            +
                  #   Gets the attribute set of the given name from internal storage.
         
     | 
| 
       129 
183 
     | 
    
         
             
                  #   @param set_name [Symbol,String] name of a set
         
     | 
| 
       130 
     | 
    
         
            -
                  #   @return [AttributeSet<String>] the  
     | 
| 
      
 184 
     | 
    
         
            +
                  #   @return [AttributeSet<String>] the attribute set
         
     | 
| 
       131 
185 
     | 
    
         
             
                  # 
         
     | 
| 
       132 
186 
     | 
    
         
             
                  # @overload attribute_set(set_name, *attribute_names)
         
     | 
| 
       133 
187 
     | 
    
         
             
                  #   Adds new attributes to a set of attributes.
         
     | 
| 
         @@ -148,13 +202,12 @@ module ActiveModel 
     | 
|
| 
       148 
202 
     | 
    
         
             
                  #   @param attribute_names [Array<Symbol,String>] names of additional attributes to be stored in set
         
     | 
| 
       149 
203 
     | 
    
         
             
                  #   @return [nil]
         
     | 
| 
       150 
204 
     | 
    
         
             
                  def attribute_set(*args)
         
     | 
| 
       151 
     | 
    
         
            -
                    AttributeFiltersHelpers.check_wanted_methods(self)
         
     | 
| 
       152 
205 
     | 
    
         
             
                    case args.size
         
     | 
| 
       153 
206 
     | 
    
         
             
                    when 0
         
     | 
| 
       154 
207 
     | 
    
         
             
                      attribute_sets
         
     | 
| 
       155 
208 
     | 
    
         
             
                    when 1
         
     | 
| 
       156 
209 
     | 
    
         
             
                      first_arg = args.first
         
     | 
| 
       157 
     | 
    
         
            -
                      if first_arg.is_a?(Hash)
         
     | 
| 
      
 210 
     | 
    
         
            +
                      if first_arg.is_a?(Hash) # multiple sets defined
         
     | 
| 
       158 
211 
     | 
    
         
             
                        first_arg.each_pair { |k, v| attribute_set(k, v) }
         
     | 
| 
       159 
212 
     | 
    
         
             
                        nil
         
     | 
| 
       160 
213 
     | 
    
         
             
                      else
         
     | 
| 
         @@ -162,19 +215,13 @@ module ActiveModel 
     | 
|
| 
       162 
215 
     | 
    
         
             
                      end
         
     | 
| 
       163 
216 
     | 
    
         
             
                    else
         
     | 
| 
       164 
217 
     | 
    
         
             
                      first_arg = args.shift
         
     | 
| 
       165 
     | 
    
         
            -
                      if first_arg.is_a?(Hash)
         
     | 
| 
      
 218 
     | 
    
         
            +
                      if first_arg.is_a?(Hash) # multiple sets defined
         
     | 
| 
       166 
219 
     | 
    
         
             
                        first_arg.each_pair do |k, v|
         
     | 
| 
       167 
220 
     | 
    
         
             
                          attribute_set(k, v, args)
         
     | 
| 
       168 
221 
     | 
    
         
             
                        end
         
     | 
| 
       169 
222 
     | 
    
         
             
                      else
         
     | 
| 
       170 
     | 
    
         
            -
                         
     | 
| 
       171 
     | 
    
         
            -
                         
     | 
| 
       172 
     | 
    
         
            -
                        atrs.each do |atr_name|
         
     | 
| 
       173 
     | 
    
         
            -
                          __attributes_to_sets_map[atr_name] ||= ActiveModel::AttributeSet.new
         
     | 
| 
       174 
     | 
    
         
            -
                          __attributes_to_sets_map[atr_name] << set_name
         
     | 
| 
       175 
     | 
    
         
            -
                        end
         
     | 
| 
       176 
     | 
    
         
            -
                        __attribute_sets[set_name] ||= ActiveModel::AttributeSet.new
         
     | 
| 
       177 
     | 
    
         
            -
                        __attribute_sets[set_name] << atrs
         
     | 
| 
      
 223 
     | 
    
         
            +
                        AttributeFiltersHelpers.check_wanted_methods(self)
         
     | 
| 
      
 224 
     | 
    
         
            +
                        add_atrs_to_set(first_arg.to_sym, *args)
         
     | 
| 
       178 
225 
     | 
    
         
             
                      end
         
     | 
| 
       179 
226 
     | 
    
         
             
                      nil
         
     | 
| 
       180 
227 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -236,7 +283,13 @@ module ActiveModel 
     | 
|
| 
       236 
283 
     | 
    
         
             
                      else
         
     | 
| 
       237 
284 
     | 
    
         
             
                        first_arg = first_arg.to_s
         
     | 
| 
       238 
285 
     | 
    
         
             
                        args.flatten.compact.each do |set_name|
         
     | 
| 
       239 
     | 
    
         
            -
                           
     | 
| 
      
 286 
     | 
    
         
            +
                          if set_name.is_a?(Hash) # annotation
         
     | 
| 
      
 287 
     | 
    
         
            +
                            set_name.each_pair do |set_name_b, a_defs|
         
     | 
| 
      
 288 
     | 
    
         
            +
                              attribute_set(set_name_b, first_arg => a_defs)
         
     | 
| 
      
 289 
     | 
    
         
            +
                            end
         
     | 
| 
      
 290 
     | 
    
         
            +
                          else
         
     | 
| 
      
 291 
     | 
    
         
            +
                            attribute_set(set_name, first_arg)
         
     | 
| 
      
 292 
     | 
    
         
            +
                          end
         
     | 
| 
       240 
293 
     | 
    
         
             
                        end
         
     | 
| 
       241 
294 
     | 
    
         
             
                      end
         
     | 
| 
       242 
295 
     | 
    
         
             
                      nil
         
     | 
| 
         @@ -250,26 +303,34 @@ module ActiveModel 
     | 
|
| 
       250 
303 
     | 
    
         
             
                  alias_method :filtered_attributes,  :filter_attribute
         
     | 
| 
       251 
304 
     | 
    
         | 
| 
       252 
305 
     | 
    
         
             
                  # Gets all the defined attribute sets.
         
     | 
| 
      
 306 
     | 
    
         
            +
                  # 
         
     | 
| 
       253 
307 
     | 
    
         
             
                  # @note Use +key+ method explicitly to check if the given set exists. The hash returned by this method
         
     | 
| 
       254 
308 
     | 
    
         
             
                  #  will always return {AttributeSet} object. If there is no such set defined then the returned,
         
     | 
| 
       255 
     | 
    
         
            -
                  #  matching set will be empty.
         
     | 
| 
      
 309 
     | 
    
         
            +
                  #  matching set will be empty. All set objects are duplicates of the defined sets.
         
     | 
| 
      
 310 
     | 
    
         
            +
                  # 
         
     | 
| 
       256 
311 
     | 
    
         
             
                  # @return [Hash{Symbol => AttributeSet<String>}] the collection of attribute sets indexed by their names
         
     | 
| 
       257 
312 
     | 
    
         
             
                  def attribute_sets
         
     | 
| 
       258 
     | 
    
         
            -
                    d =  
     | 
| 
       259 
     | 
    
         
            -
                     
     | 
| 
      
 313 
     | 
    
         
            +
                    d = Hash.new(ActiveModel::AttributeSet.new.freeze)
         
     | 
| 
      
 314 
     | 
    
         
            +
                    __attribute_sets.each_pair do |set_name, set_object|
         
     | 
| 
      
 315 
     | 
    
         
            +
                      d[set_name] = set_object.dup
         
     | 
| 
      
 316 
     | 
    
         
            +
                    end
         
     | 
| 
       260 
317 
     | 
    
         
             
                    d
         
     | 
| 
       261 
318 
     | 
    
         
             
                  end
         
     | 
| 
       262 
319 
     | 
    
         
             
                  alias_method :attributes_sets, :attribute_sets
         
     | 
| 
       263 
320 
     | 
    
         
             
                  alias_method :properties_sets, :attribute_sets
         
     | 
| 
       264 
321 
     | 
    
         | 
| 
       265 
322 
     | 
    
         
             
                  # Gets all the defined attribute set names hashed by attribute names.
         
     | 
| 
      
 323 
     | 
    
         
            +
                  # 
         
     | 
| 
       266 
324 
     | 
    
         
             
                  # @note Use +key+ method explicitly to check if the given attribute is assigned to any set. The hash
         
     | 
| 
       267 
325 
     | 
    
         
             
                  #  returned by this method will always return {AttributeSet} object. If the attribute is not assigned
         
     | 
| 
       268 
326 
     | 
    
         
             
                  #  to any set then the returned, matching set will be empty.
         
     | 
| 
      
 327 
     | 
    
         
            +
                  # 
         
     | 
| 
       269 
328 
     | 
    
         
             
                  # @return [Hash{String => AttributeSet<Symbol>}] the collection of attribute set names indexed by attribute names
         
     | 
| 
       270 
329 
     | 
    
         
             
                  def attributes_to_sets
         
     | 
| 
       271 
     | 
    
         
            -
                    d =  
     | 
| 
       272 
     | 
    
         
            -
                     
     | 
| 
      
 330 
     | 
    
         
            +
                    d = Hash.new(ActiveModel::AttributeSet.new.freeze)
         
     | 
| 
      
 331 
     | 
    
         
            +
                    __attributes_to_sets_map.each_pair do |set_name, set_object|
         
     | 
| 
      
 332 
     | 
    
         
            +
                      d[set_name] = set_object.dup
         
     | 
| 
      
 333 
     | 
    
         
            +
                    end
         
     | 
| 
       273 
334 
     | 
    
         
             
                    d
         
     | 
| 
       274 
335 
     | 
    
         
             
                  end
         
     | 
| 
       275 
336 
     | 
    
         
             
                  alias_method :attribute_sets_map, :attributes_to_sets
         
     | 
| 
         @@ -284,6 +345,35 @@ module ActiveModel 
     | 
|
| 
       284 
345 
     | 
    
         
             
                    @__attribute_sets ||= Hash.new
         
     | 
| 
       285 
346 
     | 
    
         
             
                  end
         
     | 
| 
       286 
347 
     | 
    
         | 
| 
      
 348 
     | 
    
         
            +
                  def add_atrs_to_set(set_name, *atrs)
         
     | 
| 
      
 349 
     | 
    
         
            +
                    atrs = atrs.flatten.compact
         
     | 
| 
      
 350 
     | 
    
         
            +
                    atrs.each do |atr_name|
         
     | 
| 
      
 351 
     | 
    
         
            +
                      if atr_name.is_a?(Hash) # annotation
         
     | 
| 
      
 352 
     | 
    
         
            +
                        atr_name.each_pair do |atr_name_b, a_defs|
         
     | 
| 
      
 353 
     | 
    
         
            +
                          add_atrs_to_set(set_name, atr_name_b)
         
     | 
| 
      
 354 
     | 
    
         
            +
                          s = __attribute_sets[set_name] and a_defs.nil? or a_defs.each_pair { |n, v| s.annotate(atr_name_b, n, v) }
         
     | 
| 
      
 355 
     | 
    
         
            +
                        end
         
     | 
| 
      
 356 
     | 
    
         
            +
                        return
         
     | 
| 
      
 357 
     | 
    
         
            +
                      else
         
     | 
| 
      
 358 
     | 
    
         
            +
                        atr_name = atr_name.to_s
         
     | 
| 
      
 359 
     | 
    
         
            +
                        __attributes_to_sets_map[atr_name] ||= ActiveModel::AttributeSet.new
         
     | 
| 
      
 360 
     | 
    
         
            +
                        __attributes_to_sets_map[atr_name] << set_name
         
     | 
| 
      
 361 
     | 
    
         
            +
                      end
         
     | 
| 
      
 362 
     | 
    
         
            +
                    end
         
     | 
| 
      
 363 
     | 
    
         
            +
                    __attribute_sets[set_name] ||= ActiveModel::AttributeSet.new
         
     | 
| 
      
 364 
     | 
    
         
            +
                    __attribute_sets[set_name] << atrs.map{ |a| a.to_s }.freeze
         
     | 
| 
      
 365 
     | 
    
         
            +
                  end
         
     | 
| 
       287 
366 
     | 
    
         
             
                end # module ClassMethods
         
     | 
| 
      
 367 
     | 
    
         
            +
             
     | 
| 
      
 368 
     | 
    
         
            +
                private
         
     | 
| 
      
 369 
     | 
    
         
            +
             
     | 
| 
      
 370 
     | 
    
         
            +
                # Helper that collects untracked virtual attributes that
         
     | 
| 
      
 371 
     | 
    
         
            +
                # have setters and getters.
         
     | 
| 
      
 372 
     | 
    
         
            +
                def __vatrf(no_presence_check = false)
         
     | 
| 
      
 373 
     | 
    
         
            +
                  tar = self.class.send(:__treat_as_real)
         
     | 
| 
      
 374 
     | 
    
         
            +
                  return tar if no_presence_check || tar.empty?
         
     | 
| 
      
 375 
     | 
    
         
            +
                  tar.select { |a| respond_to?(a) && respond_to?("#{a}=") }
         
     | 
| 
      
 376 
     | 
    
         
            +
                end
         
     | 
| 
      
 377 
     | 
    
         
            +
             
     | 
| 
       288 
378 
     | 
    
         
             
              end # module AttributeMethods
         
     | 
| 
       289 
379 
     | 
    
         
             
            end # module ActiveModel
         
     | 
| 
         @@ -35,6 +35,20 @@ module ActiveModel 
     | 
|
| 
       35 
35 
     | 
    
         
             
                  end
         
     | 
| 
       36 
36 
     | 
    
         
             
                  module_function :check_wanted_methods
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
      
 38 
     | 
    
         
            +
                  # @private
         
     | 
| 
      
 39 
     | 
    
         
            +
                  def each_element(value, must_be = nil, &block)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    if value.is_a?(Array)
         
     | 
| 
      
 41 
     | 
    
         
            +
                      value.map { |v| each_element(v, must_be, &block) }
         
     | 
| 
      
 42 
     | 
    
         
            +
                    elsif value.is_a?(Hash)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      value.merge(value) { |k, ov| each_element(ov, must_be, &block) }
         
     | 
| 
      
 44 
     | 
    
         
            +
                    elsif must_be.nil? || value.is_a?(must_be)
         
     | 
| 
      
 45 
     | 
    
         
            +
                      yield(value)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    else
         
     | 
| 
      
 47 
     | 
    
         
            +
                      value
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                  module_function :each_element
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
       38 
52 
     | 
    
         
             
                end # module AttributeFiltersHelpers
         
     | 
| 
       39 
53 
     | 
    
         
             
              end # module AttributeFilters
         
     | 
| 
       40 
54 
     | 
    
         
             
            end # module ActiveModel
         
     | 
| 
         @@ -6,9 +6,16 @@ describe ActiveModel::AttributeFilters do 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
              describe TestModel do
         
     | 
| 
       8 
8 
     | 
    
         
             
                before do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  TestModel.attributes_that(:should_be_stripped, :email, :real_name)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  TestModel.attributes_that(:should_be_titleized, :real_name)
         
     | 
| 
       9 
11 
     | 
    
         
             
                  @tm = TestModel.new
         
     | 
| 
       10 
12 
     | 
    
         
             
                end
         
     | 
| 
       11 
13 
     | 
    
         | 
| 
      
 14 
     | 
    
         
            +
                it "should return list of sets attribute belongs to" do
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @tm.the_attribute(:email).should include :should_be_stripped
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @tm.the_attribute('email').should include :should_be_stripped
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       12 
19 
     | 
    
         
             
                it "should be able to filter model attributes properly" do
         
     | 
| 
       13 
20 
     | 
    
         
             
                  @tm.username          = " UPCASEĄĘŚĆ      "
         
     | 
| 
       14 
21 
     | 
    
         
             
                  @tm.email             = " Some@EXAMPLE.com   "
         
     | 
| 
         @@ -19,6 +26,16 @@ describe ActiveModel::AttributeFilters do 
     | 
|
| 
       19 
26 
     | 
    
         
             
                  @tm.real_name.should  == "Sir Rails"
         
     | 
| 
       20 
27 
     | 
    
         
             
                end
         
     | 
| 
       21 
28 
     | 
    
         | 
| 
      
 29 
     | 
    
         
            +
                it "should filter model attributes that are arrays" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @tm.username          = [" UPCASEĄĘŚĆ      "]
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @tm.email             = [" Some@EXAMPLE.com   ", "  x "]
         
     | 
| 
      
 32 
     | 
    
         
            +
                  @tm.real_name         = ["       sir    rails ", nil]
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @tm.save
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @tm.username.should   == ["upcaseąęść"]
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @tm.email.should      == ["Some@EXAMPLE.com", "x"]
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @tm.real_name.should  == ["Sir Rails", nil]
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
       22 
39 
     | 
    
         
             
                it "should not filter model attributes that are blank" do
         
     | 
| 
       23 
40 
     | 
    
         
             
                  @tm.username = nil
         
     | 
| 
       24 
41 
     | 
    
         
             
                  @tm.save
         
     | 
| 
         @@ -45,19 +62,323 @@ describe ActiveModel::AttributeFilters do 
     | 
|
| 
       45 
62 
     | 
    
         
             
                  @tm.test_attribute.should == 'unchanged'
         
     | 
| 
       46 
63 
     | 
    
         
             
                end
         
     | 
| 
       47 
64 
     | 
    
         | 
| 
      
 65 
     | 
    
         
            +
                it "should operate on annotations" do
         
     | 
| 
      
 66 
     | 
    
         
            +
                  s = @tm.attributes_that(:should_be_stripped)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  c = @tm.attributes_that(:should_be_titleized)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  s.annotate(:real_name, :operation, :first_value)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  s.annotate(:email,     :operation, :e_value)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  c.annotate(:real_name, :operation, :some_value)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  c.annotate(:real_name, :operation, :other_value)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  s.instance_eval{annotations}.should ==  { 'real_name' => { :operation => :first_value }, 'email' => { :operation => :e_value } }
         
     | 
| 
      
 73 
     | 
    
         
            +
                  c.instance_eval{annotations}.should ==  { 'real_name' => { :operation => :other_value } }
         
     | 
| 
      
 74 
     | 
    
         
            +
                  -> {TestModel.class_eval do
         
     | 
| 
      
 75 
     | 
    
         
            +
                    attributes_that should_be_sth: [ :abc, :atr_one => {:ak => "av"}, :atr_two => {:sk => "sv"} ]
         
     | 
| 
      
 76 
     | 
    
         
            +
                    attributes_that should_be_sth: [:atr_three, :atr_two, :yy]
         
     | 
| 
      
 77 
     | 
    
         
            +
                    attributes_that should_be_sth: {:atr_three => {:fak => "fav"}, :atr_two => {:flala => "flala2"}, :fyy => nil}
         
     | 
| 
      
 78 
     | 
    
         
            +
                    annotate_attribute_set should_be_sth: {:atr_three => {:ak => "av"}, :atr_two => {:lala => "lala2"}, :yy => nil}
         
     | 
| 
      
 79 
     | 
    
         
            +
                    annotate_attribute_set should_be_sth: [:atr_three, :oo => "oe"]
         
     | 
| 
      
 80 
     | 
    
         
            +
                    annotate_attribute_set should_be_sth: [:atr_three, :aa, "bb"]
         
     | 
| 
      
 81 
     | 
    
         
            +
                    annotate_attribute_set should_be_sth: [:atr_three, :hh, "hh"]
         
     | 
| 
      
 82 
     | 
    
         
            +
                    annotate_attributes_that :should_be_sth, :atr_three, :six => 6
         
     | 
| 
      
 83 
     | 
    
         
            +
                    annotate_attribute_set :should_be_sth => [:atr_three, :cc, "dd"]
         
     | 
| 
      
 84 
     | 
    
         
            +
                    annotate_attribute_set :should_be_sth => [:atr_three, :ccc, "ddd"]
         
     | 
| 
      
 85 
     | 
    
         
            +
                    delete_annotation_from_set :should_be_sth, :atr_three, :ccc
         
     | 
| 
      
 86 
     | 
    
         
            +
                    delete_annotation_from_set :should_be_sth => { :atr_three => [ :hh ] }
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end}.should_not raise_error
         
     | 
| 
      
 88 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_one).should == {:ak => "av"}
         
     | 
| 
      
 89 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_two, :lala).should == "lala2"
         
     | 
| 
      
 90 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_x, :lalax).should == nil
         
     | 
| 
      
 91 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_three, :oo).should == "oe"
         
     | 
| 
      
 92 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_three, :aa).should == "bb"
         
     | 
| 
      
 93 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_three, :cc).should == "dd"
         
     | 
| 
      
 94 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_three, :ccc).should == nil
         
     | 
| 
      
 95 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_three, :six).should == 6
         
     | 
| 
      
 96 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).has_annotations?.should == true
         
     | 
| 
      
 97 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).has_annotation?(:atr_three).should == true
         
     | 
| 
      
 98 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).has_annotation?(:atr_three, :ak).should == true
         
     | 
| 
      
 99 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).has_annotation?(:atr_nope).should == false
         
     | 
| 
      
 100 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).has_annotation?(:atr_three, :nope).should == false
         
     | 
| 
      
 101 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).delete_annotation(:atr_three, :cc)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_three, :cc).should == "dd"
         
     | 
| 
      
 103 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_three, :hh).should == nil
         
     | 
| 
      
 104 
     | 
    
         
            +
                  dupx = TestModel.attributes_that(:should_be_sth)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  dupy = @tm.attributes_that(:should_be_sth)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  dupx.send(:annotations).should == dupy.send(:annotations) 
         
     | 
| 
      
 107 
     | 
    
         
            +
                  dupx.object_id.should_not == dupy.object_id
         
     | 
| 
      
 108 
     | 
    
         
            +
                  -> {TestModel.class_eval do
         
     | 
| 
      
 109 
     | 
    
         
            +
                    annotate_attributes_that :should_be_sth => { :atr_three => { :cc => "ee" } }
         
     | 
| 
      
 110 
     | 
    
         
            +
                    annotate_attribute_set should_be_sth: [:atr_three, :oo => "of"]
         
     | 
| 
      
 111 
     | 
    
         
            +
                    attributes_that should_be_sth: { :atr_one => {:ak => "ax"} }
         
     | 
| 
      
 112 
     | 
    
         
            +
                  end}.should_not raise_error
         
     | 
| 
      
 113 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_three, :cc).should == "ee"
         
     | 
| 
      
 114 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_three, :oo).should == "of"
         
     | 
| 
      
 115 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_one).should == {:ak => "ax"}
         
     | 
| 
      
 116 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_sth).annotation(:atr_two, :lala).should == "lala2"
         
     | 
| 
      
 117 
     | 
    
         
            +
                end
         
     | 
| 
      
 118 
     | 
    
         
            +
              end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
              describe "AttributeSet set operations" do
         
     | 
| 
      
 121 
     | 
    
         
            +
                before do
         
     | 
| 
      
 122 
     | 
    
         
            +
                  TestModel.attributes_that(:should_be_stripped, :email, :real_name)
         
     | 
| 
      
 123 
     | 
    
         
            +
                  TestModel.attributes_that(:should_be_titleized, :real_name)
         
     | 
| 
      
 124 
     | 
    
         
            +
                  @tm = TestModel.new
         
     | 
| 
      
 125 
     | 
    
         
            +
                  @s = @tm.attributes_that(:should_be_stripped)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  @c = @tm.attributes_that(:should_be_titleized)
         
     | 
| 
      
 127 
     | 
    
         
            +
                  @s.annotate(:real_name, :operation, :first_value)
         
     | 
| 
      
 128 
     | 
    
         
            +
                  @s.annotate(:email,     :operation, :e_value)
         
     | 
| 
      
 129 
     | 
    
         
            +
                  @c.annotate(:real_name, :operation, :some_value)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  @c.annotate(:real_name, :operation, :other_value)
         
     | 
| 
      
 131 
     | 
    
         
            +
                end
         
     | 
| 
      
 132 
     | 
    
         
            +
              
         
     | 
| 
      
 133 
     | 
    
         
            +
                it "should be able to relatively complement sets" do
         
     | 
| 
      
 134 
     | 
    
         
            +
                  r = @s - @c
         
     | 
| 
      
 135 
     | 
    
         
            +
                  r.to_a.sort.should == [ "email", "username" ]
         
     | 
| 
      
 136 
     | 
    
         
            +
                  r.instance_eval{annotations}.should == { 'email' => { :operation => :e_value } }
         
     | 
| 
      
 137 
     | 
    
         
            +
                end
         
     | 
| 
      
 138 
     | 
    
         
            +
              
         
     | 
| 
      
 139 
     | 
    
         
            +
                it "should be able to join sets (union)" do
         
     | 
| 
      
 140 
     | 
    
         
            +
                  r = @s + @c
         
     | 
| 
      
 141 
     | 
    
         
            +
                  r.to_a.sort.should == [ "email", "real_name", "username" ]
         
     | 
| 
      
 142 
     | 
    
         
            +
                  r.instance_eval{annotations}.should == { 'email' => { :operation => :e_value }, 'real_name' => { :operation => :first_value } }
         
     | 
| 
      
 143 
     | 
    
         
            +
                end
         
     | 
| 
      
 144 
     | 
    
         
            +
              
         
     | 
| 
      
 145 
     | 
    
         
            +
                it "should be able to intersect sets" do
         
     | 
| 
      
 146 
     | 
    
         
            +
                  r = @s & @c
         
     | 
| 
      
 147 
     | 
    
         
            +
                  r.to_a.sort.should == [ "real_name" ]
         
     | 
| 
      
 148 
     | 
    
         
            +
                  r.instance_eval{annotations}.should == { 'real_name' => { :operation => :first_value } }
         
     | 
| 
      
 149 
     | 
    
         
            +
                end
         
     | 
| 
      
 150 
     | 
    
         
            +
              
         
     | 
| 
      
 151 
     | 
    
         
            +
                it "should be able to exclusively disjunct sets" do
         
     | 
| 
      
 152 
     | 
    
         
            +
                  r = @s ^ @c
         
     | 
| 
      
 153 
     | 
    
         
            +
                  r.to_a.sort.should == [ "email", "username" ]
         
     | 
| 
      
 154 
     | 
    
         
            +
                  r.instance_eval{annotations}.should == { 'email' => { :operation => :e_value } }
         
     | 
| 
      
 155 
     | 
    
         
            +
                  sp = @s.dup
         
     | 
| 
      
 156 
     | 
    
         
            +
                  sp.annotate(:username, 'k', 'v')
         
     | 
| 
      
 157 
     | 
    
         
            +
                  r = sp ^ @c
         
     | 
| 
      
 158 
     | 
    
         
            +
                  r.to_a.sort.should == [ "email", "username" ]
         
     | 
| 
      
 159 
     | 
    
         
            +
                  r.instance_eval{annotations}.should == { 'email' => { :operation => :e_value }, 'username' => { :k => "v" } }
         
     | 
| 
      
 160 
     | 
    
         
            +
                end
         
     | 
| 
      
 161 
     | 
    
         
            +
              
         
     | 
| 
      
 162 
     | 
    
         
            +
                it "should be able to delete elements from a set" do
         
     | 
| 
      
 163 
     | 
    
         
            +
                  @s.annotate(:username, :some_key, 'string_val')
         
     | 
| 
      
 164 
     | 
    
         
            +
                  @s.instance_eval{annotations}.should == { 'email' => { :operation => :e_value }, 'real_name' => { :operation => :first_value },
         
     | 
| 
      
 165 
     | 
    
         
            +
                                             'username' => { :some_key => 'string_val' } }
         
     | 
| 
      
 166 
     | 
    
         
            +
                  @s.delete_if { |o| o == 'username' }
         
     | 
| 
      
 167 
     | 
    
         
            +
                  @s.include?('username').should == false
         
     | 
| 
      
 168 
     | 
    
         
            +
                  @s.instance_eval{annotations}.should == { 'email' => { :operation => :e_value }, 'real_name' => { :operation => :first_value } }
         
     | 
| 
      
 169 
     | 
    
         
            +
                end
         
     | 
| 
      
 170 
     | 
    
         
            +
              
         
     | 
| 
      
 171 
     | 
    
         
            +
                it "should be able to keep elements in a set using keep_if" do
         
     | 
| 
      
 172 
     | 
    
         
            +
                  @s.keep_if { |o| o == 'email' }
         
     | 
| 
      
 173 
     | 
    
         
            +
                  @s.include?('email').should == true
         
     | 
| 
      
 174 
     | 
    
         
            +
                  @s.instance_eval{annotations}.should == { 'email' => { :operation => :e_value } }
         
     | 
| 
      
 175 
     | 
    
         
            +
                end
         
     | 
| 
       48 
176 
     | 
    
         
             
              end
         
     | 
| 
       49 
177 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
               
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
                   
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
                   
     | 
| 
       57 
     | 
    
         
            -
                   
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
                  
         
     | 
| 
      
 178 
     | 
    
         
            +
              describe ActiveModel::AttributeFilters::Common do
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                before do
         
     | 
| 
      
 181 
     | 
    
         
            +
                  TestModel.class_eval do
         
     | 
| 
      
 182 
     | 
    
         
            +
                    include ActiveModel::AttributeFilters::Common
         
     | 
| 
      
 183 
     | 
    
         
            +
                    @__attribute_sets = nil
         
     | 
| 
      
 184 
     | 
    
         
            +
                  end
         
     | 
| 
      
 185 
     | 
    
         
            +
                  @tm = TestModel.new
         
     | 
| 
      
 186 
     | 
    
         
            +
                end
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                after do
         
     | 
| 
      
 189 
     | 
    
         
            +
                  TestModel.class_eval{@__attribute_sets = nil}
         
     | 
| 
      
 190 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_splitted).should be_empty
         
     | 
| 
      
 191 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_joined).should be_empty
         
     | 
| 
      
 192 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_splitted).annotation(:real_name).should == nil
         
     | 
| 
      
 193 
     | 
    
         
            +
                  @tm.attributes_that(:should_be_joined).annotation(:real_name).should == nil 
         
     | 
| 
      
 194 
     | 
    
         
            +
                end
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                shared_examples "splitting" do |ev|
         
     | 
| 
      
 197 
     | 
    
         
            +
                  before { TestModel.class_eval{before_save :split_attributes} }
         
     | 
| 
      
 198 
     | 
    
         
            +
                  it "should split attributes using syntax: #{ev}" do
         
     | 
| 
      
 199 
     | 
    
         
            +
                    TestModel.class_eval(ev)
         
     | 
| 
      
 200 
     | 
    
         
            +
                    @tm.real_name = "Paweł Wilk Trzy"
         
     | 
| 
      
 201 
     | 
    
         
            +
                    @tm.first_name = nil
         
     | 
| 
      
 202 
     | 
    
         
            +
                    @tm.last_name = nil
         
     | 
| 
      
 203 
     | 
    
         
            +
                    #-> { @tm.save }.should_not raise_error
         
     | 
| 
      
 204 
     | 
    
         
            +
                    @tm.save
         
     | 
| 
      
 205 
     | 
    
         
            +
                    @tm.first_name.should == 'Paweł'
         
     | 
| 
      
 206 
     | 
    
         
            +
                    @tm.last_name.should == 'Wilk'
         
     | 
| 
      
 207 
     | 
    
         
            +
                    @tm.first_name = nil
         
     | 
| 
      
 208 
     | 
    
         
            +
                    @tm.last_name = nil
         
     | 
| 
      
 209 
     | 
    
         
            +
                    @tm.real_name = "Paweł"
         
     | 
| 
      
 210 
     | 
    
         
            +
                    -> { @tm.save }.should_not raise_error
         
     | 
| 
      
 211 
     | 
    
         
            +
                    @tm.first_name.should == 'Paweł'
         
     | 
| 
      
 212 
     | 
    
         
            +
                    @tm.last_name.should == nil
         
     | 
| 
      
 213 
     | 
    
         
            +
                  end
         
     | 
| 
      
 214 
     | 
    
         
            +
                end
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
                shared_examples "splitting_array" do |de, ev, rn|
         
     | 
| 
      
 217 
     | 
    
         
            +
                  before do
         
     | 
| 
      
 218 
     | 
    
         
            +
                    TestModel.class_eval{before_save :split_attributes}
         
     | 
| 
      
 219 
     | 
    
         
            +
                  end
         
     | 
| 
      
 220 
     | 
    
         
            +
                  it "should split array attribute #{de}" do
         
     | 
| 
      
 221 
     | 
    
         
            +
                    TestModel.class_eval(ev)
         
     | 
| 
      
 222 
     | 
    
         
            +
                    @tm.real_name = rn
         
     | 
| 
      
 223 
     | 
    
         
            +
                    @tm.first_name = nil
         
     | 
| 
      
 224 
     | 
    
         
            +
                    @tm.last_name = nil
         
     | 
| 
      
 225 
     | 
    
         
            +
                    -> { @tm.save }.should_not raise_error
         
     | 
| 
      
 226 
     | 
    
         
            +
                    @tm.first_name.should == 'Paweł'
         
     | 
| 
      
 227 
     | 
    
         
            +
                    @tm.last_name.should == 'Wilk'
         
     | 
| 
      
 228 
     | 
    
         
            +
                  end
         
     | 
| 
      
 229 
     | 
    
         
            +
                end
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
                context "with split_attribute" do
         
     | 
| 
      
 232 
     | 
    
         
            +
                  include_examples "splitting", "split_attribute :real_name => [ :first_name, :last_name ]"
         
     | 
| 
      
 233 
     | 
    
         
            +
                  include_examples "splitting", "split_attribute :real_name, [ :first_name, :last_name ]"
         
     | 
| 
      
 234 
     | 
    
         
            +
                  include_examples "splitting", "split_attribute :real_name => { :into => [ :first_name, :last_name ] }"
         
     | 
| 
      
 235 
     | 
    
         
            +
                  include_examples "splitting", "split_attribute :real_name, :into => [ :first_name, :last_name ]"
         
     | 
| 
      
 236 
     | 
    
         
            +
                end
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
                context "with attributes_that" do
         
     | 
| 
      
 239 
     | 
    
         
            +
                  include_examples "splitting", "attributes_that :should_be_splitted => { :real_name => { :split_into => [:first_name, :last_name] } }"
         
     | 
| 
      
 240 
     | 
    
         
            +
                  include_examples "splitting", "attributes_that :should_be_splitted => [ :real_name => { :split_into => [:first_name, :last_name] } ]"
         
     | 
| 
      
 241 
     | 
    
         
            +
                end
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
                context "with the_attribute" do
         
     | 
| 
      
 244 
     | 
    
         
            +
                  include_examples "splitting", "the_attribute :real_name => { :should_be_splitted => { :split_into => [:first_name, :last_name] } }"
         
     | 
| 
      
 245 
     | 
    
         
            +
                  include_examples "splitting", "the_attribute :real_name => [ :should_be_splitted => { :split_into => [:first_name, :last_name] } ]"
         
     | 
| 
      
 246 
     | 
    
         
            +
                  include_examples "splitting", "the_attribute :real_name, [ :should_be_splitted => { :split_into => [:first_name, :last_name] } ]"
         
     | 
| 
      
 247 
     | 
    
         
            +
                end
         
     | 
| 
       62 
248 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
      
 249 
     | 
    
         
            +
                context "with no pattern and no limit" do
         
     | 
| 
      
 250 
     | 
    
         
            +
                  include_examples "splitting_array", "", "split_attribute :real_name => { :into => [ :first_name, :last_name ], :flatten => true }",
         
     | 
| 
      
 251 
     | 
    
         
            +
                                                      ["Paweł", "Wilk", "Trzy"]
         
     | 
| 
      
 252 
     | 
    
         
            +
                end
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
                context "with a single space pattern and without a limit" do
         
     | 
| 
      
 255 
     | 
    
         
            +
                  include_examples  "splitting_array", "having 3 elements",
         
     | 
| 
      
 256 
     | 
    
         
            +
                                    "split_attribute :real_name => {:pattern => ' ', :into => [ :first_name, :last_name ], :flatten => true}",
         
     | 
| 
      
 257 
     | 
    
         
            +
                                    ["Paweł", "Wilk", "Trzy"]
         
     | 
| 
      
 258 
     | 
    
         
            +
                  include_examples  "splitting_array", "having 2 elements and first containing pattern (space)",
         
     | 
| 
      
 259 
     | 
    
         
            +
                                    "split_attribute :real_name => {:pattern => ' ', :into => [ :first_name, :last_name ], :flatten => true}",
         
     | 
| 
      
 260 
     | 
    
         
            +
                                    ["Paweł Wilk", "Trzy"]
         
     | 
| 
      
 261 
     | 
    
         
            +
                end
         
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
                context "with a single space pattern and with a limit" do
         
     | 
| 
      
 264 
     | 
    
         
            +
                  include_examples  "splitting_array", "having 3 elements",
         
     | 
| 
      
 265 
     | 
    
         
            +
                                    "split_attribute :real_name => {:pattern => ' ', :limit => 2, :into => [ :first_name, :last_name ], :flatten => true}",
         
     | 
| 
      
 266 
     | 
    
         
            +
                                    ["Paweł", "Wilk", "Trzy"]
         
     | 
| 
      
 267 
     | 
    
         
            +
                  include_examples  "splitting_array", "having 2 elements and first containing pattern (space)",
         
     | 
| 
      
 268 
     | 
    
         
            +
                                    "split_attribute :real_name => {:pattern => ' ', :limit => 2, :into => [ :first_name, :last_name ], :flatten => true}",
         
     | 
| 
      
 269 
     | 
    
         
            +
                                    ["Paweł Wilk", "Trzy"]
         
     | 
| 
      
 270 
     | 
    
         
            +
                  include_examples  "splitting_array", "having 2 elements and first containing pattern (space)",
         
     | 
| 
      
 271 
     | 
    
         
            +
                                    "split_attribute :real_name => {:pattern => ' ', :limit => 10, :into => [ :first_name, :last_name ], :flatten => true}",
         
     | 
| 
      
 272 
     | 
    
         
            +
                                    ["Paweł", "Wilk"]
         
     | 
| 
      
 273 
     | 
    
         
            +
                  include_examples  "splitting_array", "having 1 element and first containing pattern (space)",
         
     | 
| 
      
 274 
     | 
    
         
            +
                                    "split_attribute :real_name => {:pattern => ' ', :limit => 2, :into => [ :first_name, :last_name ], :flatten => true}",
         
     | 
| 
      
 275 
     | 
    
         
            +
                                    ["Paweł Wilk"]
         
     | 
| 
      
 276 
     | 
    
         
            +
                  it "should split array attribute having 2 elements and second containing pattern (space)" do
         
     | 
| 
      
 277 
     | 
    
         
            +
                    TestModel.class_eval{split_attribute :real_name => {:pattern => ' ', :limit => 2, :into => [ :first_name, :last_name ], :flatten => true}}
         
     | 
| 
      
 278 
     | 
    
         
            +
                    @tm.real_name = ["Paweł", "Wilk Trzy", "Cztery"]
         
     | 
| 
      
 279 
     | 
    
         
            +
                    @tm.first_name = nil
         
     | 
| 
      
 280 
     | 
    
         
            +
                    @tm.last_name = nil
         
     | 
| 
      
 281 
     | 
    
         
            +
                    -> { @tm.save }.should_not raise_error
         
     | 
| 
      
 282 
     | 
    
         
            +
                    @tm.first_name.should == 'Paweł'
         
     | 
| 
      
 283 
     | 
    
         
            +
                    @tm.last_name.should == 'Wilk'
         
     | 
| 
      
 284 
     | 
    
         
            +
                  end
         
     | 
| 
      
 285 
     | 
    
         
            +
                end
         
     | 
| 
      
 286 
     | 
    
         
            +
             
     | 
| 
      
 287 
     | 
    
         
            +
                context "without a pattern and with a limit" do
         
     | 
| 
      
 288 
     | 
    
         
            +
                  include_examples  "splitting_array", "having 3 elements",
         
     | 
| 
      
 289 
     | 
    
         
            +
                                    "split_attribute :real_name => {:limit => 2, :into => [ :first_name, :last_name ], :flatten => true}",
         
     | 
| 
      
 290 
     | 
    
         
            +
                                    ["Paweł", "Wilk", "Trzy"]
         
     | 
| 
      
 291 
     | 
    
         
            +
                  include_examples  "splitting_array", "having 2 elements",
         
     | 
| 
      
 292 
     | 
    
         
            +
                                    "split_attribute :real_name => {:limit => 2, :into => [ :first_name, :last_name ], :flatten => true}",
         
     | 
| 
      
 293 
     | 
    
         
            +
                                    ["Paweł", "Wilk"]
         
     | 
| 
      
 294 
     | 
    
         
            +
                end
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
                it "should split array attribute with the destination in the same place" do
         
     | 
| 
      
 297 
     | 
    
         
            +
                  TestModel.class_eval{split_attribute :real_name => { :flatten => true } }
         
     | 
| 
      
 298 
     | 
    
         
            +
                  TestModel.class_eval{before_save :split_attributes}
         
     | 
| 
      
 299 
     | 
    
         
            +
                  @tm.real_name = ["Paweł", "Wilk Trzy", "Cztery"]
         
     | 
| 
      
 300 
     | 
    
         
            +
                  @tm.first_name = nil
         
     | 
| 
      
 301 
     | 
    
         
            +
                  @tm.last_name = nil
         
     | 
| 
      
 302 
     | 
    
         
            +
                  -> { @tm.save }.should_not raise_error
         
     | 
| 
      
 303 
     | 
    
         
            +
                  @tm.first_name.should == nil
         
     | 
| 
      
 304 
     | 
    
         
            +
                  @tm.last_name.should == nil
         
     | 
| 
      
 305 
     | 
    
         
            +
                  @tm.real_name.should == ["Paweł", "Wilk", "Trzy", "Cztery"]
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
                  TestModel.class_eval{split_attribute :real_name => {:limit => 2}}
         
     | 
| 
      
 308 
     | 
    
         
            +
                  @tm.real_name = ["Paweł", "Wilk Trzy Osiem Dziewiec", "Cztery"]
         
     | 
| 
      
 309 
     | 
    
         
            +
                  -> { @tm.save }.should_not raise_error
         
     | 
| 
      
 310 
     | 
    
         
            +
                  @tm.real_name.should == [["Paweł"], ["Wilk", "Trzy Osiem Dziewiec"], ["Cztery"]]
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
                  TestModel.class_eval{split_attribute :real_name => {:limit => 2, :pattern => ' '}}
         
     | 
| 
      
 313 
     | 
    
         
            +
                  @tm.real_name = ["Paweł", "Wilk Trzy", "Cztery"]
         
     | 
| 
      
 314 
     | 
    
         
            +
                  -> { @tm.save }.should_not raise_error
         
     | 
| 
      
 315 
     | 
    
         
            +
                  @tm.real_name.should == [["Paweł"], ["Wilk", "Trzy"], ["Cztery"]]
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
                  TestModel.class_eval{split_attribute :real_name => {:pattern => ' '}}
         
     | 
| 
      
 318 
     | 
    
         
            +
                  @tm.real_name = ["Paweł", "Wilk Trzy", "Cztery"]
         
     | 
| 
      
 319 
     | 
    
         
            +
                  -> { @tm.save }.should_not raise_error
         
     | 
| 
      
 320 
     | 
    
         
            +
                  @tm.real_name.should == [["Paweł"], ["Wilk", "Trzy"], ["Cztery"]]
         
     | 
| 
      
 321 
     | 
    
         
            +
                end
         
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
      
 323 
     | 
    
         
            +
                shared_examples "joining" do |ev,rn,rns,rnt|
         
     | 
| 
      
 324 
     | 
    
         
            +
                  before do
         
     | 
| 
      
 325 
     | 
    
         
            +
                    TestModel.class_eval do
         
     | 
| 
      
 326 
     | 
    
         
            +
                      before_save :join_attributes
         
     | 
| 
      
 327 
     | 
    
         
            +
                    end
         
     | 
| 
      
 328 
     | 
    
         
            +
                  end
         
     | 
| 
      
 329 
     | 
    
         
            +
                  it "should join attributes using syntax: #{ev}" do
         
     | 
| 
      
 330 
     | 
    
         
            +
                    TestModel.class_eval(ev)
         
     | 
| 
      
 331 
     | 
    
         
            +
                    # source attributes are strings:
         
     | 
| 
      
 332 
     | 
    
         
            +
                    @tm.real_name = rn
         
     | 
| 
      
 333 
     | 
    
         
            +
                    @tm.first_name = "Paweł"
         
     | 
| 
      
 334 
     | 
    
         
            +
                    @tm.last_name = "Wilk"
         
     | 
| 
      
 335 
     | 
    
         
            +
                    -> { @tm.save }.should_not raise_error
         
     | 
| 
      
 336 
     | 
    
         
            +
                    @tm.first_name.should == 'Paweł'
         
     | 
| 
      
 337 
     | 
    
         
            +
                    @tm.last_name.should == 'Wilk'
         
     | 
| 
      
 338 
     | 
    
         
            +
                    @tm.real_name.should == 'Paweł Wilk'
         
     | 
| 
      
 339 
     | 
    
         
            +
                    # source attributes are strings and nils:
         
     | 
| 
      
 340 
     | 
    
         
            +
                    @tm.first_name = "Paweł"
         
     | 
| 
      
 341 
     | 
    
         
            +
                    @tm.last_name = nil
         
     | 
| 
      
 342 
     | 
    
         
            +
                    @tm.real_name = rns
         
     | 
| 
      
 343 
     | 
    
         
            +
                    @tm.class.annotate_attributes_that(:should_be_joined, :real_name, :join_compact, true)
         
     | 
| 
      
 344 
     | 
    
         
            +
                    -> { @tm.save }.should_not raise_error
         
     | 
| 
      
 345 
     | 
    
         
            +
                    @tm.first_name.should == 'Paweł'
         
     | 
| 
      
 346 
     | 
    
         
            +
                    @tm.last_name.should == nil
         
     | 
| 
      
 347 
     | 
    
         
            +
                    @tm.real_name.should == 'Paweł'
         
     | 
| 
      
 348 
     | 
    
         
            +
                    # source attributes are arrays and strings:
         
     | 
| 
      
 349 
     | 
    
         
            +
                    @tm.first_name = ["Paweł", "Wilk"]
         
     | 
| 
      
 350 
     | 
    
         
            +
                    @tm.last_name = "Trzeci"
         
     | 
| 
      
 351 
     | 
    
         
            +
                    @tm.real_name = rnt
         
     | 
| 
      
 352 
     | 
    
         
            +
                    -> { @tm.save }.should_not raise_error
         
     | 
| 
      
 353 
     | 
    
         
            +
                    @tm.real_name.should == 'Paweł Wilk Trzeci'
         
     | 
| 
      
 354 
     | 
    
         
            +
                    
         
     | 
| 
      
 355 
     | 
    
         
            +
                  end
         
     | 
| 
      
 356 
     | 
    
         
            +
                end
         
     | 
| 
      
 357 
     | 
    
         
            +
             
     | 
| 
      
 358 
     | 
    
         
            +
                context "with join_attributes" do
         
     | 
| 
      
 359 
     | 
    
         
            +
                  include_examples "joining", "join_attributes :real_name", ["Paweł", "Wilk"], ["Paweł"], ["Paweł", "Wilk", "Trzeci"] 
         
     | 
| 
      
 360 
     | 
    
         
            +
                  include_examples "joining", "join_attributes :real_name", ["Paweł Wilk"], ["Paweł"], ["Paweł Wilk", "Trzeci"]
         
     | 
| 
      
 361 
     | 
    
         
            +
                  include_examples "joining", "join_attributes :real_name", "Paweł Wilk", "Paweł", "Paweł Wilk Trzeci"
         
     | 
| 
      
 362 
     | 
    
         
            +
                  include_examples "joining", "join_attributes :real_name => [ :first_name, :last_name ]"
         
     | 
| 
      
 363 
     | 
    
         
            +
                  include_examples "joining", "join_attributes :real_name, [ :first_name, :last_name ]"
         
     | 
| 
      
 364 
     | 
    
         
            +
                  include_examples "joining", "join_attributes :real_name => { :from => [ :first_name, :last_name ] }"
         
     | 
| 
      
 365 
     | 
    
         
            +
                  include_examples "joining", "join_attributes :real_name, :from => [ :first_name, :last_name ]"
         
     | 
| 
      
 366 
     | 
    
         
            +
                  include_examples "joining", "join_attributes [ :first_name, :last_name ] => :real_name"
         
     | 
| 
      
 367 
     | 
    
         
            +
                  include_examples "joining", "join_attributes [ :first_name, :last_name ], :real_name"
         
     | 
| 
      
 368 
     | 
    
         
            +
                  include_examples "joining", "join_attributes [ :first_name, :last_name ] => { :into => :real_name }"
         
     | 
| 
      
 369 
     | 
    
         
            +
                end
         
     | 
| 
      
 370 
     | 
    
         
            +
             
     | 
| 
      
 371 
     | 
    
         
            +
                context "with attributes_that" do
         
     | 
| 
      
 372 
     | 
    
         
            +
                  include_examples "joining", "attributes_that :should_be_joined => { :real_name => { :join_from => [:first_name, :last_name] } }"
         
     | 
| 
      
 373 
     | 
    
         
            +
                  include_examples "joining", "attributes_that :should_be_joined => [ :real_name => { :join_from => [:first_name, :last_name] } ]"
         
     | 
| 
      
 374 
     | 
    
         
            +
                end
         
     | 
| 
      
 375 
     | 
    
         
            +
             
     | 
| 
      
 376 
     | 
    
         
            +
                context "with the_attribute" do
         
     | 
| 
      
 377 
     | 
    
         
            +
                  include_examples "joining", "the_attribute :real_name => { :should_be_joined => { :join_from => [:first_name, :last_name] } }"
         
     | 
| 
      
 378 
     | 
    
         
            +
                  include_examples "joining", "the_attribute :real_name => [ :should_be_joined => { :join_from => [:first_name, :last_name] } ]"
         
     | 
| 
      
 379 
     | 
    
         
            +
                  include_examples "joining", "the_attribute :real_name, [ :should_be_joined => { :join_from => [:first_name, :last_name] } ]"
         
     | 
| 
      
 380 
     | 
    
         
            +
                end
         
     | 
| 
      
 381 
     | 
    
         
            +
             
     | 
| 
      
 382 
     | 
    
         
            +
              end # describe ActiveModel::AttributeFilters::Common
         
     | 
| 
      
 383 
     | 
    
         
            +
             
     | 
| 
      
 384 
     | 
    
         
            +
            end # describe ActiveModel::AttributeFilters
         
     |