attr_bucket 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module AttrBucket
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/attr_bucket.rb CHANGED
@@ -32,9 +32,12 @@ module AttrBucket
32
32
  def attr_bucket(opts = {})
33
33
  unless include? InstanceMethods
34
34
  include InstanceMethods
35
-
36
- class_attribute :bucketed_attributes
37
- self.bucketed_attributes = []
35
+ class_attribute :_attr_bucketed_attributes
36
+ self._attr_bucketed_attributes = []
37
+ class_attribute :_attr_bucket_methods
38
+ # We define our methods on this module so we can override and super
39
+ self._attr_bucket_methods = Module.new
40
+ include self._attr_bucket_methods
38
41
  end
39
42
 
40
43
  return nil unless table_exists?
@@ -49,13 +52,11 @@ module AttrBucket
49
52
 
50
53
  if attrs.is_a?(Hash)
51
54
  attrs.map do|attr_name, attr_type|
52
- define_bucket_reader bucket_name, attr_name
53
- define_bucket_writer bucket_name, attr_name, attr_type, bucket_column.class
55
+ _define_bucket bucket_name, attr_name, attr_type, bucket_column.class
54
56
  end
55
57
  else
56
58
  Array.wrap(attrs).each do |attr_name|
57
- define_bucket_reader bucket_name, attr_name
58
- define_bucket_writer bucket_name, attr_name, :string, bucket_column.class
59
+ _define_bucket bucket_name, attr_name, :string, bucket_column.class
59
60
  end
60
61
  end
61
62
  end
@@ -63,33 +64,28 @@ module AttrBucket
63
64
 
64
65
  alias :i_has_a_bucket :attr_bucket
65
66
 
66
- def define_bucket_reader(bucket_name, attr_name) #:nodoc:
67
- self.bucketed_attributes += [attr_name.to_s]
68
- define_method attr_name do
69
- get_attr_bucket(bucket_name)[attr_name]
70
- end unless method_defined? attr_name
71
- end
67
+ def _define_bucket(bucket_name, attr_name, attr_type, column_class)
68
+ self._attr_bucketed_attributes |= [attr_name.to_s]
69
+
70
+ self._attr_bucket_methods.class_eval do
71
+ define_method attr_name do
72
+ _get_bucket(bucket_name)[attr_name]
73
+ end
72
74
 
73
- def define_bucket_writer(bucket_name, attr_name, attr_type, column_class) #:nodoc:
74
- define_method "#{attr_name}=" do |val|
75
- # TODO: Make this more resilient/granular for multiple bucketed changes
76
- send("#{bucket_name}_will_change!")
77
- typecasted = explicitly_type_cast(val, attr_type, column_class)
78
- get_attr_bucket(bucket_name)[attr_name] = typecasted
79
- end unless method_defined? "#{attr_name}="
75
+ define_method "#{attr_name}=" do |val|
76
+ send "#{bucket_name}_will_change!"
77
+ typecasted = _explicitly_type_cast(val, attr_type, column_class)
78
+ _get_bucket(bucket_name)[attr_name] = typecasted
79
+ end
80
+ end
80
81
  end
81
82
 
82
83
  module InstanceMethods
83
- # Retrieve the attribute bucket, or if it's not yet a Hash,
84
- # initialize it as one.
85
- def get_attr_bucket(name)
86
- unless self[name].is_a?(Hash)
87
- self[name] = {}
88
- end
89
- self[name]
84
+ def _get_bucket(bucket_name)
85
+ self[bucket_name] ||= {}
90
86
  end
91
87
 
92
- def valid_class(value, type)
88
+ def _valid_class?(value, type)
93
89
  case type
94
90
  when :integer then Fixnum === value
95
91
  when :float then Float === value
@@ -109,7 +105,7 @@ module AttrBucket
109
105
  # dates/times for bucketed columns and handle them ourselves
110
106
  # before passing the remainder on for ActiveRecord::Base to handle.
111
107
  def assign_multiparameter_attributes(pairs)
112
- bucket_pairs = pairs.select {|p| self.class.bucketed_attributes.include?(p.first.split('(').first)}
108
+ bucket_pairs = pairs.select {|p| self.class._attr_bucketed_attributes.include?(p.first.split('(').first)}
113
109
  extract_callstack_for_multiparameter_attributes(bucket_pairs).each do |name, value|
114
110
  send(name + '=', value.compact.empty? ? nil : value)
115
111
  end
@@ -122,7 +118,7 @@ module AttrBucket
122
118
  #
123
119
  # This allows custom typecasting by supplying a proc, etc
124
120
  # as the value side of the hash in an attr_bucket definition.
125
- def explicitly_type_cast(value, type, column_class)
121
+ def _explicitly_type_cast(value, type, column_class)
126
122
  return nil if value.nil?
127
123
 
128
124
  return type.call(value) if type.respond_to?(:call)
@@ -133,21 +129,21 @@ module AttrBucket
133
129
  when :integer then value.to_i rescue value ? 1 : 0
134
130
  when :float then value.to_f
135
131
  when :decimal then column_class.value_to_decimal(value)
136
- when :datetime then cast_to_time(value, column_class)
137
- when :timestamp then cast_to_time(value, column_class)
138
- when :time then cast_to_time(value, column_class, true)
139
- when :date then cast_to_date(value, column_class)
132
+ when :datetime then _cast_to_time(value, column_class)
133
+ when :timestamp then _cast_to_time(value, column_class)
134
+ when :time then _cast_to_time(value, column_class, true)
135
+ when :date then _cast_to_date(value, column_class)
140
136
  when :binary then column_class.binary_to_string(value)
141
137
  when :boolean then column_class.value_to_boolean(value)
142
138
  else value
143
139
  end
144
140
 
145
- raise ArgumentError, "Unable to typecast #{value} to #{type}" unless valid_class(typecasted, type)
141
+ raise ArgumentError, "Unable to typecast #{value} to #{type}" unless _valid_class?(typecasted, type)
146
142
 
147
143
  typecasted
148
144
  end
149
145
 
150
- def cast_to_date(value, column_class)
146
+ def _cast_to_date(value, column_class)
151
147
  if value.is_a?(Array)
152
148
  begin
153
149
  values = value.collect { |v| v.nil? ? 1 : v }
@@ -160,7 +156,7 @@ module AttrBucket
160
156
  end
161
157
  end
162
158
 
163
- def cast_to_time(value, column_class, dummy_time = false)
159
+ def _cast_to_time(value, column_class, dummy_time = false)
164
160
  if value.is_a?(Array)
165
161
  value[0] ||= Date.today.year
166
162
  Time.time_with_datetime_fallback(self.class.default_timezone, *value)
@@ -19,6 +19,23 @@ describe AttrBucket do
19
19
  @o = an_object_with_bucket :bucket => :nickname
20
20
  end
21
21
 
22
+ it 'should have our anonymous module for its immediate ancestor' do
23
+ mod = @o.class.ancestors[1]
24
+ mod.instance_methods(false).should include :nickname
25
+ end
26
+
27
+ it 'should not have a nickname method in its class' do
28
+ @o.class.instance_methods(false).should_not include :nickname
29
+ end
30
+
31
+ it 'should be able to override methods and use super' do
32
+ @o.nickname = 'John'
33
+ def @o.nickname
34
+ "Jimmy #{super}"
35
+ end
36
+ @o.nickname.should eq 'Jimmy John'
37
+ end
38
+
22
39
  it 'should cast nickname to string' do
23
40
  @o.nickname = 42
24
41
  @o.nickname.should eq '42'
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: attr_bucket
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.1
5
+ version: 0.4.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ernie Miller
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-02-12 00:00:00 -05:00
13
+ date: 2011-02-19 00:00:00 -05:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency