attr_bucket 0.1.2 → 0.2.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/Rakefile CHANGED
@@ -1,2 +1,8 @@
1
1
  require 'bundler'
2
+ require 'rspec/core/rake_task'
3
+
2
4
  Bundler::GemHelper.install_tasks
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => :spec
data/attr_bucket.gemspec CHANGED
@@ -12,7 +12,9 @@ Gem::Specification.new do |s|
12
12
  s.summary = %q{Your model can has a bucket (for its attributes).}
13
13
  s.description = %q{Store a few extra (non-searchable) attributes away in a bucket. This is probably a horrible idea, but try it anyway.}
14
14
 
15
- s.add_runtime_dependency(%q<activerecord>, ["~> 3.0.0"])
15
+ s.add_runtime_dependency 'activerecord', '~> 3.0.0'
16
+ s.add_development_dependency 'rspec', '~> 2.4.0'
17
+ s.add_development_dependency 'sqlite3'
16
18
 
17
19
  s.rubyforge_project = "attr_bucket"
18
20
 
data/lib/attr_bucket.rb CHANGED
@@ -14,6 +14,22 @@ module AttrBucket
14
14
  read_attribute(name)
15
15
  end
16
16
 
17
+ def valid_class(value, type)
18
+ case type
19
+ when :integer then Fixnum === value
20
+ when :float then Float === value
21
+ when :decimal then BigDecimal === value
22
+ when :datetime then Time === value
23
+ when :date then Date === value
24
+ when :timestamp then Time === value
25
+ when :time then Time === value
26
+ when :text, :string then String === value
27
+ when :binary then String === value
28
+ when :boolean then [TrueClass, FalseClass].grep value
29
+ else false
30
+ end
31
+ end
32
+
17
33
  # Swipe the nifty column typecasting from the column class
18
34
  # underlying the bucket column, or use the call method of
19
35
  # the object supplied for +type+ if it responds to call.
@@ -25,7 +41,7 @@ module AttrBucket
25
41
 
26
42
  return type.call(value) if type.respond_to?(:call)
27
43
 
28
- case type
44
+ typecasted = case type
29
45
  when :string then value.to_s
30
46
  when :text then value.to_s
31
47
  when :integer then value.to_i rescue value ? 1 : 0
@@ -39,6 +55,10 @@ module AttrBucket
39
55
  when :boolean then column_class.value_to_boolean(value)
40
56
  else value
41
57
  end
58
+
59
+ raise ArgumentError, "Unable to typecast #{value} to #{type}" unless valid_class(typecasted, type)
60
+
61
+ typecasted
42
62
  end
43
63
 
44
64
  module ClassMethods
@@ -107,6 +127,7 @@ module AttrBucket
107
127
  define_method "#{attr_name}=" do |val|
108
128
  # TODO: Make this more resilient/granular for multiple bucketed changes
109
129
  send("#{bucket_name}_will_change!")
130
+ typecasted = explicitly_type_cast(val, attr_type, column_class)
110
131
  get_attr_bucket(bucket_name)[attr_name] = explicitly_type_cast(val, attr_type, column_class)
111
132
  end unless method_defined? "#{attr_name}="
112
133
  end
@@ -1,3 +1,3 @@
1
1
  module AttrBucket
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,139 @@
1
+ require 'spec_helper'
2
+
3
+ describe AttrBucket do
4
+
5
+ it 'should define an private attr_bucket method in AR::Base' do
6
+ ActiveRecord::Base.private_methods.should include :attr_bucket
7
+ end
8
+
9
+ it 'should define an i_has_a_bucket alias in AR::Base' do
10
+ ActiveRecord::Base.private_methods.should include :i_has_a_bucket
11
+ end
12
+
13
+ it 'should raise an ArgumentError when defining a bucket on a non-text column' do
14
+ expect { a_class_with_bucket :name => :blah }.to raise_error ArgumentError
15
+ end
16
+
17
+ context 'object with a bucketed attribute named "nickname"' do
18
+ before do
19
+ @o = an_object_with_bucket :bucket => :nickname
20
+ end
21
+
22
+ it 'should cast nickname to string' do
23
+ @o.nickname = 42
24
+ @o.nickname.should eq '42'
25
+ end
26
+
27
+ it 'should support validations' do
28
+ @o.class.validates_presence_of :nickname
29
+ expect { @o.save! }.to raise_error ActiveRecord::RecordInvalid
30
+ end
31
+
32
+ it 'should maintain bucketed attributes when saved' do
33
+ @o.nickname = 'Headly von Headenstein'
34
+ @o.save
35
+
36
+ persisted_item.nickname.should eq 'Headly von Headenstein'
37
+ end
38
+ end
39
+
40
+ context 'object with bucketed attributes in array format' do
41
+ before do
42
+ @o = an_object_with_bucket :bucket => [:quest, :favorite_color]
43
+ end
44
+
45
+ it 'should cast all values to strings' do
46
+ @o.quest = 1
47
+ @o.favorite_color = 2
48
+
49
+ [@o.quest, @o.favorite_color].should eq ['1', '2']
50
+ end
51
+ end
52
+
53
+ context 'object with bucketed attributes in hash format' do
54
+ before do
55
+ @o = an_object_with_bucket :bucket => {
56
+ :summary => :text,
57
+ :age => :integer,
58
+ :body_temp => :float,
59
+ :salary => :decimal,
60
+ :hired_at => :datetime,
61
+ :stamp => :timestamp,
62
+ :workday_starts_at => :time,
63
+ :birthday => :date,
64
+ :binary_data => :binary,
65
+ :is_awesome => :boolean,
66
+ :processed_name => proc { |val| "PROCESSED: #{val}" }
67
+ }
68
+ end
69
+
70
+ it 'typecasts to String for :text' do
71
+ @o.summary = 12345
72
+ @o.summary.should be_a String
73
+ @o.summary.should eq '12345'
74
+ end
75
+
76
+ it 'typecasts to Fixnum for :integer' do
77
+ @o.age = '33'
78
+ @o.age.should be_a Fixnum
79
+ @o.age.should eq 33
80
+ end
81
+
82
+ it 'typecasts to Float for :float' do
83
+ @o.body_temp = '98.6'
84
+ @o.body_temp.should be_a Float
85
+ @o.body_temp.should eq 98.6
86
+ end
87
+
88
+ it 'typecasts to BigDecimal for :decimal' do
89
+ @o.salary = '50000.23'
90
+ @o.salary.should be_a BigDecimal
91
+ @o.salary.should eq 50000.23
92
+ end
93
+
94
+ it 'typecasts to Time for :datetime' do
95
+ @o.hired_at = '2011-01-01 08:00:00'
96
+ @o.hired_at.should be_a Time
97
+ @o.hired_at.should eq Time.parse '2011-01-01 08:00:00'
98
+ end
99
+
100
+ it 'typecasts to Time for :timestamp' do
101
+ @o.stamp = '2011-01-01 08:00:00'
102
+ @o.stamp.should be_a Time
103
+ @o.stamp.should eq Time.parse '2011-01-01 08:00:00'
104
+ end
105
+
106
+ it 'typecasts to dummy Time for :time' do
107
+ @o.workday_starts_at = '08:00:00'
108
+ @o.workday_starts_at.should be_a Time
109
+ @o.workday_starts_at.should eq Time.parse '2000-01-01 08:00:00'
110
+ end
111
+
112
+ it 'typecasts to Date for :date in string format' do
113
+ @o.birthday = '1977/8/29'
114
+ @o.birthday.should be_a Date
115
+ @o.birthday.should eq Date.new(1977, 8, 29)
116
+ end
117
+
118
+ it 'typecasts to String for :binary' do
119
+ @o.binary_data = File.read(__FILE__)
120
+ @o.binary_data.should be_a String
121
+ @o.binary_data.should match /@o.binary_data.should match/ # ooh, meta.
122
+ end
123
+
124
+ it 'typecasts to TrueClass/FalseClass for :boolean' do
125
+ @o.is_awesome = '1'
126
+ @o.should be_awesome
127
+ end
128
+
129
+ it 'performs custom processing when an attribute has a proc "type"' do
130
+ @o.processed_name = 'Ernie'
131
+ @o.processed_name.should be_a String
132
+ @o.processed_name.should eq 'PROCESSED: Ernie'
133
+ end
134
+
135
+ it 'should raise ArgumentError if unable to typecast a value' do
136
+ expect { @o.stamp = 123456 }.to raise_error ArgumentError
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,15 @@
1
+ module AttrBucketHelper
2
+ def a_class_with_bucket(opts)
3
+ Item.delete_all
4
+ Object.send :remove_const, :AttrBucketItem if Object.const_defined? :AttrBucketItem
5
+ Object.const_set :AttrBucketItem, Class.new(Item) { attr_bucket opts }
6
+ end
7
+
8
+ def an_object_with_bucket(opts)
9
+ a_class_with_bucket(opts).new
10
+ end
11
+
12
+ def persisted_item
13
+ AttrBucketItem.first
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'attr_bucket'
4
+
5
+ Dir[File.expand_path('../{helpers,support}/*.rb', __FILE__)].each do |f|
6
+ require f
7
+ end
8
+
9
+ RSpec.configure do |config|
10
+ config.before :suite do
11
+ Schema.create
12
+ end
13
+
14
+ config.include AttrBucketHelper
15
+ end
@@ -0,0 +1,27 @@
1
+ ActiveRecord::Base.establish_connection(
2
+ :adapter => 'sqlite3',
3
+ :database => ':memory:'
4
+ )
5
+
6
+ class Item < ActiveRecord::Base
7
+ def awesome?
8
+ respond_to?(:is_awesome) && is_awesome
9
+ end
10
+ end
11
+
12
+ module Schema
13
+ def self.create
14
+ ActiveRecord::Base.silence do
15
+ ActiveRecord::Migration.verbose = false
16
+
17
+ ActiveRecord::Schema.define do
18
+ create_table :items, :force => true do |t|
19
+ t.string :name
20
+ t.string :type
21
+ t.text :bucket
22
+ t.text :other_bucket
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
7
  - 2
9
- version: 0.1.2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ernie Miller
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-28 00:00:00 -05:00
17
+ date: 2011-01-29 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -32,6 +32,34 @@ dependencies:
32
32
  version: 3.0.0
33
33
  type: :runtime
34
34
  version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 2
45
+ - 4
46
+ - 0
47
+ version: 2.4.0
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: sqlite3
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :development
62
+ version_requirements: *id003
35
63
  description: Store a few extra (non-searchable) attributes away in a bucket. This is probably a horrible idea, but try it anyway.
36
64
  email:
37
65
  - ernie@metautonomo.us
@@ -50,6 +78,10 @@ files:
50
78
  - attr_bucket.gemspec
51
79
  - lib/attr_bucket.rb
52
80
  - lib/attr_bucket/version.rb
81
+ - spec/attr_bucket_spec.rb
82
+ - spec/helpers/attr_bucket_helper.rb
83
+ - spec/spec_helper.rb
84
+ - spec/support/schema.rb
53
85
  has_rdoc: true
54
86
  homepage: http://metautonomo.us
55
87
  licenses: []
@@ -82,5 +114,8 @@ rubygems_version: 1.3.7
82
114
  signing_key:
83
115
  specification_version: 3
84
116
  summary: Your model can has a bucket (for its attributes).
85
- test_files: []
86
-
117
+ test_files:
118
+ - spec/attr_bucket_spec.rb
119
+ - spec/helpers/attr_bucket_helper.rb
120
+ - spec/spec_helper.rb
121
+ - spec/support/schema.rb