attribute_mapper 1.3.0 → 1.3.1

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.
@@ -1,12 +1,12 @@
1
1
  module AttributeMapper
2
-
2
+
3
3
  def self.included(model)
4
4
  model.extend ClassMethods
5
5
  model.send(:include, InstanceMethods)
6
6
  end
7
-
7
+
8
8
  module ClassMethods # @private
9
-
9
+
10
10
  # Map a column in your table to a human-friendly attribute on your
11
11
  # model. When +attribute+ is accessed, it will return the key
12
12
  # from the mapping hash. When the attribute is updated, the value
@@ -25,6 +25,7 @@ module AttributeMapper
25
25
  # Each attribute you map generates an options method, suitable for
26
26
  # use in form helpers. If you define an attribute +status+,
27
27
  # instances of your model will have a +status_options+ method
28
+ # (on the class and any instances)
28
29
  # that returns a sorted array of arrays containing
29
30
  # humanized-option-name/value pairs. By default this array is
30
31
  # sorted by the option name (closed/open/etc.) If you'd rather
@@ -42,16 +43,32 @@ module AttributeMapper
42
43
  # @option options :predicate_methods Generate methods for checking
43
44
  # whether an object has a certain attribute set
44
45
  def map_attribute(attribute, options)
45
- mapping = options[:to]
46
+ mapping = build_mapping(options)
46
47
  verify_existence_of attribute
47
48
  add_accessor_for attribute, mapping
48
49
  add_predicates_for attribute, mapping.keys if options.fetch(:predicate_methods) { true }
49
50
  override attribute
50
51
  add_options_helper_for attribute, mapping
52
+ add_options_helper_to_class attribute, self
51
53
  end
52
54
 
53
55
  private
54
-
56
+ def build_mapping(options)
57
+ case options[:to]
58
+ when Hash
59
+ options[:to]
60
+ when Array
61
+ build_mapping_from_array(options[:to])
62
+ end
63
+ end
64
+
65
+ # Transforms an array into a hash for the mapping.
66
+ # [:open, :closed] # => { :open => 1, :closed => 2 }
67
+ #
68
+ def build_mapping_from_array(array)
69
+ array.enum_for(:each_with_index).inject({}) { |h, (o, i)| h[o] = i+1; h }
70
+ end
71
+
55
72
  def add_accessor_for(attribute, mapping)
56
73
  class_eval(<<-EVAL, __FILE__, __LINE__)
57
74
  class << self
@@ -78,18 +95,30 @@ module AttributeMapper
78
95
  options = self.class.#{attribute.to_s.pluralize}.sort { |l, r|
79
96
  sort_by_keys ? l.first.to_s <=> r.first.to_s : l.last <=> r.last
80
97
  }.map { |f|
81
- [f[0].to_s.humanize, f[0]]
98
+ [f[0].to_s.capitalize, f[0]]
82
99
  }
83
- self.#{attribute}.present? ? [options, {:selected => self.#{attribute}}] : [options]
100
+ self.#{attribute}.present? ? [options, {:selected => self.#{attribute}}] : [options]
84
101
  end
85
102
  EVAL
86
103
  end
87
-
104
+
105
+ def add_options_helper_to_class(attribute, klass)
106
+ klass.instance_eval(<<-EVAL, __FILE__, __LINE__)
107
+ def #{attribute}_options(sort_by_keys=true)
108
+ options = #{attribute.to_s.pluralize}.sort { |l, r|
109
+ sort_by_keys ? l.first.to_s <=> r.first.to_s : l.last <=> r.last
110
+ }.map { |f|
111
+ [f[0].to_s.capitalize, f[0]]
112
+ }
113
+ end
114
+ EVAL
115
+ end
116
+
88
117
  def override(*args)
89
118
  override_getters *args
90
119
  override_setters *args
91
120
  end
92
-
121
+
93
122
  def override_getters(attribute)
94
123
  class_eval(<<-EVAL, __FILE__, __LINE__)
95
124
  def #{attribute}
@@ -97,7 +126,7 @@ module AttributeMapper
97
126
  end
98
127
  EVAL
99
128
  end
100
-
129
+
101
130
  def override_setters(attribute)
102
131
  class_eval(<<-EVAL, __FILE__, __LINE__)
103
132
  def #{attribute}=(raw_value)
@@ -106,15 +135,15 @@ module AttributeMapper
106
135
  end
107
136
  EVAL
108
137
  end
109
-
138
+
110
139
  def verify_existence_of(attribute)
111
140
  raise ArgumentError, "`#{attribute}' is not an attribute of `#{self}'" unless column_names.include?(attribute.to_s)
112
141
  end
113
-
142
+
114
143
  end
115
-
144
+
116
145
  module InstanceMethods
117
-
146
+
118
147
  private
119
148
 
120
149
  def resolve_value_of(attribute, raw_value)
@@ -126,5 +155,5 @@ module AttributeMapper
126
155
  end
127
156
 
128
157
  end
129
-
158
+
130
159
  end
@@ -1,17 +1,17 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class AttributeMapperTest < Test::Unit::TestCase
4
-
4
+
5
5
  context "Attribute Mapper" do
6
6
  setup do
7
7
  Ticket.map_attribute :status, :to => mapping
8
8
  end
9
-
9
+
10
10
  should "set mapping for each attribute" do
11
11
  assert_equal mapping[:open], Ticket.statuses[:open]
12
12
  assert_equal mapping[:closed], Ticket.statuses[:closed]
13
13
  end
14
-
14
+
15
15
  should "override getters and setters" do
16
16
  assert_nil ticket.status
17
17
  assert_nothing_raised do
@@ -19,11 +19,11 @@ class AttributeMapperTest < Test::Unit::TestCase
19
19
  end
20
20
  assert_equal :open, ticket.status
21
21
  assert_equal mapping[:open], ticket[:status]
22
-
22
+
23
23
  assert_nothing_raised do
24
24
  ticket.status = :closed
25
25
  end
26
-
26
+
27
27
  assert_equal :closed, ticket.status
28
28
  assert_equal mapping[:closed], ticket[:status]
29
29
  end
@@ -32,7 +32,7 @@ class AttributeMapperTest < Test::Unit::TestCase
32
32
  ticket.status = :open
33
33
  assert ticket.open?
34
34
  end
35
-
35
+
36
36
  should "allow indifferent access to setters" do
37
37
  assert_nothing_raised do
38
38
  ticket.status = :open
@@ -43,27 +43,27 @@ class AttributeMapperTest < Test::Unit::TestCase
43
43
  end
44
44
  assert_equal :open, ticket.status
45
45
  end
46
-
46
+
47
47
  should "raise an exception when trying to map to a non-existent column" do
48
48
  assert_raises(ArgumentError) do
49
49
  Ticket.map_attribute :this_column_does_not_exist, :to => {:i_will_fail => 1}
50
50
  end
51
51
  end
52
-
52
+
53
53
  should "raise an exception when setting an invalid value" do
54
54
  assert_raises(ArgumentError) do
55
55
  ticket.status = :non_existent_value
56
56
  end
57
57
  end
58
-
58
+
59
59
  should "allow setting a primitive value directly if the value is present in the mapping" do
60
60
  ticket = Ticket.new
61
61
  assert_nothing_raised do
62
62
  ticket.status = mapping[:open]
63
63
  end
64
-
64
+
65
65
  assert_equal :open, ticket.status
66
-
66
+
67
67
  assert_raises(ArgumentError) do
68
68
  ticket.status = 500
69
69
  end
@@ -76,10 +76,10 @@ class AttributeMapperTest < Test::Unit::TestCase
76
76
  should "work with attr_accessible" do
77
77
  new_ticket = Class.new(ActiveRecord::Base) do
78
78
  set_table_name "tickets"
79
-
79
+
80
80
  include AttributeMapper
81
81
  map_attribute :status, :to => {:open => 1, :closed => 2}
82
-
82
+
83
83
  attr_accessible :status
84
84
  end
85
85
 
@@ -95,6 +95,40 @@ class AttributeMapperTest < Test::Unit::TestCase
95
95
  ticket.status = :open
96
96
  assert_equal [[["Open", :open], ["Closed", :closed]], {:selected => :open}], ticket.status_options(false)
97
97
  end
98
+
99
+ should "provide a class level helper for forms" do
100
+ assert_equal [["Closed", :closed], ["Open", :open]], Ticket.status_options
101
+ assert_equal [["Open", :open], ["Closed", :closed]], Ticket.status_options(false)
102
+ end
103
+
104
+ should "not raise an error when setting to a blank value" do
105
+ assert_nothing_raised {
106
+ ticket.update_attributes(:status => "")
107
+ }
108
+ end
109
+
110
+ should "not raise an error when setting to a nil value" do
111
+ assert_nothing_raised {
112
+ ticket.update_attributes(:status => nil)
113
+ }
114
+ end
115
+
116
+ should "turn off generation of predicate methods" do
117
+ new_ticket = Class.new(ActiveRecord::Base) do
118
+ set_table_name "tickets"
119
+
120
+ include AttributeMapper
121
+ map_attribute :status, :to => {:open => 1, :closed => 2}, :predicate_methods => false
122
+ end
123
+
124
+ t = new_ticket.new
125
+ t.status = :open
126
+
127
+ assert_raises(NoMethodError) {
128
+ t.open?
129
+ }
130
+ end
131
+
98
132
 
99
133
  context "setting nil as a valid value in the mapping" do
100
134
  setup do
@@ -120,46 +154,44 @@ class AttributeMapperTest < Test::Unit::TestCase
120
154
 
121
155
  end
122
156
 
123
- should "not raise an error when setting to a blank value" do
124
- assert_nothing_raised {
125
- ticket.update_attributes(:status => "")
126
- }
127
- end
128
-
129
- should "not raise an error when setting to a nil value" do
130
- assert_nothing_raised {
131
- ticket.update_attributes(:status => nil)
132
- }
133
- end
134
-
135
- should "turn off generation of predicate methods" do
136
- new_ticket = Class.new(ActiveRecord::Base) do
157
+ should 'auto-expand arrays to a hash with the raw value being the index + 1' do
158
+ array_ticket = Class.new(ActiveRecord::Base) do
137
159
  set_table_name "tickets"
138
160
 
139
161
  include AttributeMapper
140
- map_attribute :status, :to => {:open => 1, :closed => 2}, :predicate_methods => false
162
+ map_attribute :status, :to => [:open, :closed]
141
163
  end
142
164
 
143
- t = new_ticket.new
144
- t.status = :open
165
+ ticket = array_ticket.new
166
+
167
+ assert_nil ticket.status
168
+ assert_nothing_raised do
169
+ ticket.status = :open
170
+ end
171
+ assert_equal :open, ticket.status
172
+ assert_equal mapping[:open], ticket[:status]
173
+
174
+ assert_nothing_raised do
175
+ ticket.status = :closed
176
+ end
177
+
178
+ assert_equal :closed, ticket.status
179
+ assert_equal mapping[:closed], ticket[:status]
145
180
 
146
- assert_raises(NoMethodError) {
147
- t.open?
148
- }
149
181
  end
150
-
182
+
151
183
  end
152
-
184
+
153
185
  #######
154
186
  private
155
187
  #######
156
-
188
+
157
189
  def mapping(options = {})
158
190
  {:open => 1, :closed => 2}.merge(options)
159
191
  end
160
-
192
+
161
193
  def ticket
162
194
  @ticket ||= Ticket.new
163
195
  end
164
-
196
+
165
197
  end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attribute_mapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 3
9
+ - 1
10
+ version: 1.3.1
5
11
  platform: ruby
6
12
  authors:
7
13
  - Marcel Molina Jr.
@@ -38,21 +44,27 @@ rdoc_options:
38
44
  require_paths:
39
45
  - lib
40
46
  required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
41
48
  requirements:
42
49
  - - ">="
43
50
  - !ruby/object:Gem::Version
51
+ hash: 3
52
+ segments:
53
+ - 0
44
54
  version: "0"
45
- version:
46
55
  required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
47
57
  requirements:
48
58
  - - ">="
49
59
  - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
50
63
  version: "0"
51
- version:
52
64
  requirements: []
53
65
 
54
66
  rubyforge_project:
55
- rubygems_version: 1.3.5
67
+ rubygems_version: 1.3.7
56
68
  signing_key:
57
69
  specification_version: 3
58
70
  summary: Map symbolic types to primitive types and stash them in a column.