activerecord-hstore_properties 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,5 +17,15 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
 
20
+
21
+ gem.add_dependency 'activesupport', '>= 3.2.12'
22
+ gem.add_dependency 'activerecord-postgres-hstore', '>= 0.7.5'
23
+
20
24
  gem.add_development_dependency "rspec"
21
- end
25
+ gem.add_development_dependency "sqlite3"
26
+ gem.add_development_dependency "activerecord", '>= 3.2.12'
27
+ gem.add_development_dependency "with_model"
28
+ gem.add_development_dependency "with_model", "~> 0.3.1"
29
+ gem.add_development_dependency "pry"
30
+
31
+ end
@@ -1,35 +1,20 @@
1
+ require 'active_support/core_ext/class'
2
+ require 'active_support/concern'
1
3
  require "active_record/properties/base"
2
4
  require "active_record/properties/boolean_property"
3
5
  require "active_record/properties/counter_property"
4
6
  require "active_record/properties/number_property"
5
7
  require "active_record/properties/string_property"
6
- require "active_record/properties/extensions/booleans"
7
- require "active_record/properties/extensions/counters"
8
8
 
9
9
  module ActiveRecord
10
10
  module HstoreProperties
11
11
  extend ActiveSupport::Concern
12
12
 
13
13
  included do
14
- include ActiveRecord::Properties::Extensions::Booleans
15
- include ActiveRecord::Properties::Extensions::Counters
16
-
17
14
  serialize :properties, ::ActiveRecord::Coders::Hstore
18
15
  class_attribute :_properties
19
16
  end
20
17
 
21
- def define_property_method(method_name, suffix, &block)
22
- if method_name.ends_with?(suffix) and (self.class._properties.detect { |pn| pn.name.to_s == method_name.sub(suffix, '') })
23
- prop_name = method_name.sub(suffix, '')
24
- self.class.send(:define_method, method_name) do
25
- block.call(prop_name, self)
26
- end
27
- [true, block.call(prop_name, self)]
28
- else
29
- [false, nil]
30
- end
31
- end
32
-
33
18
  module ClassMethods
34
19
  def properties_set(*args)
35
20
  self._properties.dup.tap do |all_properties|
@@ -45,13 +30,9 @@ module ActiveRecord
45
30
  self._properties ||= []
46
31
  else
47
32
  self._properties ||= []
48
-
49
33
  new_properties = extract_properties(args)
50
34
  self._properties += new_properties
51
-
52
- new_properties.each do |property|
53
- define_method("#{property.name.to_s}_property") { properties[property.name.to_s] }
54
- end
35
+ define_accessors_for(new_properties)
55
36
  end
56
37
  end
57
38
 
@@ -61,6 +42,24 @@ module ActiveRecord
61
42
 
62
43
  private
63
44
 
45
+ def define_accessors_for(properties)
46
+ properties.each do |property|
47
+ property.class.property_accessors.each do |suffixes, proc|
48
+
49
+ method_names = suffixes.map{|suffix| "#{property.name}#{suffix}"}
50
+ primary_method_name = method_names.shift
51
+
52
+ #Define main method once...
53
+ define_method(primary_method_name) do
54
+ self.instance_exec(property, &proc)
55
+ end
56
+
57
+ #... and then define aliases
58
+ method_names.each { |method_name| alias_method(method_name, primary_method_name) }
59
+ end
60
+ end
61
+ end
62
+
64
63
  def extract_properties(args)
65
64
  typed_properties = args.extract_options!
66
65
 
@@ -1,6 +1,23 @@
1
1
  module ActiveRecord
2
2
  module Properties
3
3
  class Base < Struct.new(:name)
4
+ class_attribute :_property_accessors
5
+
6
+ class << self
7
+ def property_accessors
8
+ self._property_accessors || {}
9
+ end
10
+
11
+ def add_property_accessor(*suffixes, &block)
12
+ self._property_accessors ||= {}
13
+ self._property_accessors = _property_accessors.merge(suffixes.to_a => block)
14
+ end
15
+ end
16
+
17
+ add_property_accessor '_property' do |property|
18
+ properties[property.name.to_s]
19
+ end
20
+
4
21
  end
5
22
  end
6
23
  end
@@ -4,6 +4,24 @@ module ActiveRecord
4
4
  def formtastic_options
5
5
  {:as => :boolean, :checked_value => 'true', :unchecked_value => 'false'}
6
6
  end
7
+
8
+ add_property_accessor '_enabled?', '?' do |property|
9
+ ::ActiveRecord::ConnectionAdapters::Column.value_to_boolean(properties[property.name.to_s])
10
+ end
11
+
12
+ add_property_accessor '_raise!', '_enable!' do |property|
13
+ _properties = self.properties
14
+ _properties[property.name] = true
15
+ update_column(:properties, ActiveRecord::Coders::Hstore.new({}).dump(_properties))
16
+ _properties[property.name]
17
+ end
18
+
19
+ add_property_accessor '_lower!', '_disable!' do |property|
20
+ _properties = self.properties
21
+ _properties[property.name] = false
22
+ update_column(:properties, ActiveRecord::Coders::Hstore.new({}).dump(_properties))
23
+ _properties[property.name]
24
+ end
7
25
  end
8
26
  end
9
27
  end
@@ -4,6 +4,18 @@ module ActiveRecord
4
4
  def formtastic_options
5
5
  {:as => :number, :disabled => true}
6
6
  end
7
+
8
+ add_property_accessor '_count' do |property|
9
+ properties[property.name].to_i
10
+ end
11
+
12
+ add_property_accessor '_bump!' do |property|
13
+ _properties = self.properties
14
+ _properties[property.name] = self[property.name].to_i + 1
15
+ update_column(:properties, ActiveRecord::Coders::Hstore.new({}).dump(_properties))
16
+ _properties[property.name]
17
+ end
18
+
7
19
  end
8
20
  end
9
- end
21
+ end
@@ -1,5 +1,5 @@
1
1
  module Activerecord
2
2
  module HstoreProperties
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.4"
4
4
  end
5
5
  end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+ describe ActiveRecord::HstoreProperties do
3
+ with_model :Comment do
4
+ table do |t|
5
+ t.string :text
6
+ t.hstore :properties
7
+ end
8
+
9
+ model do
10
+ include ActiveRecord::HstoreProperties
11
+
12
+ #We need to do that, as sqlite does not support hstore
13
+ self.class_eval do
14
+ def properties
15
+ self[:properties].is_a?(Hash) ? self[:properties] : ActiveRecord::Coders::Hstore.load(self[:properties])
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ it "it should respond to properties call" do
22
+ Comment.respond_to?(:properties).should be_true
23
+ end
24
+
25
+ it "it should be possible to define properties" do
26
+ Comment.properties 'property_one', 'property_two'
27
+ Comment.properties.should be_an_instance_of(Array)
28
+ Comment.properties.map(&:name).should include('property_one', 'property_two')
29
+ end
30
+
31
+ it "by default properties should be of String type" do
32
+ Comment.properties 'property_one'
33
+ Comment.properties.first.should be_a_kind_of(ActiveRecord::Properties::StringProperty)
34
+ end
35
+
36
+ it "it should be possible to define property types other than string" do
37
+ Comment.properties 'property_one', 'property_two' => :boolean
38
+ Comment.properties.find { |p| p.name == 'property_two' }.should be_a_kind_of(ActiveRecord::Properties::BooleanProperty)
39
+ end
40
+
41
+ it "_property accessor should return raw property value" do
42
+ Comment.properties 'property_two' => :boolean
43
+ comment = Comment.new
44
+ comment.properties = {:property_two => true}
45
+ comment.save
46
+ comment.property_two_property.should == 'true'
47
+ end
48
+
49
+ it "properties_set should not return underscored properties" do
50
+ Comment.properties '_property_one', 'property_two'
51
+ Comment.properties_set.find{|p| p.name == '_property_one'}.should be_nil
52
+ Comment.properties_set.find{|p| p.name == 'property_two'}.should_not be_nil
53
+ end
54
+
55
+ context "boolean properties" do
56
+ before(:each) do
57
+ Comment.properties 'property_two' => :boolean
58
+ @comment = Comment.new
59
+ @comment.properties = {:property_two => true}
60
+ @comment.save
61
+ end
62
+
63
+ it "should be possible to be queried for state" do
64
+ @comment.property_two?.should == true
65
+ @comment.property_two_enabled?.should == true
66
+ end
67
+
68
+ it "should be possible to be toggled" do
69
+ @comment.property_two_lower!
70
+ @comment.property_two?.should == false
71
+ @comment.property_two_raise!
72
+ @comment.property_two?.should == true
73
+ @comment.property_two_disable!
74
+ @comment.property_two?.should == false
75
+ @comment.property_two_enable!
76
+ @comment.property_two?.should == true
77
+ end
78
+ end
79
+
80
+ context "counter properties" do
81
+ before(:each) do
82
+ Comment.properties 'property_two' => :counter
83
+ @comment = Comment.new
84
+ @comment.save
85
+ end
86
+
87
+ it "should be possible to bump counter" do
88
+ @comment.property_two_bump!
89
+ @comment.properties['property_two'].should == '1'
90
+ end
91
+
92
+ it "should be possible to query for current count" do
93
+ @comment.property_two_count.should == 0
94
+ @comment.property_two_bump!
95
+
96
+ @comment.property_two_count.should == 1
97
+ end
98
+
99
+ end
100
+
101
+ end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,14 @@
1
- require 'activerecord-hstore_properties'
1
+ require 'activerecord-hstore_properties'
2
+ require 'with_model'
3
+ require 'active_record'
4
+ require 'activerecord-postgres-hstore'
5
+ require 'pry'
6
+
7
+ RSpec.configure do |config|
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => 'sqlite3',
10
+ :database => ':memory:'
11
+ )
12
+
13
+ config.extend WithModel
14
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-hstore_properties
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,40 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-18 00:00:00.000000000 Z
12
+ date: 2013-04-11 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.12
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.12
30
+ - !ruby/object:Gem::Dependency
31
+ name: activerecord-postgres-hstore
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 0.7.5
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 0.7.5
14
46
  - !ruby/object:Gem::Dependency
15
47
  name: rspec
16
48
  requirement: !ruby/object:Gem::Requirement
@@ -27,6 +59,86 @@ dependencies:
27
59
  - - ! '>='
28
60
  - !ruby/object:Gem::Version
29
61
  version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: sqlite3
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: activerecord
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: 3.2.12
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: 3.2.12
94
+ - !ruby/object:Gem::Dependency
95
+ name: with_model
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: with_model
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 0.3.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: 0.3.1
126
+ - !ruby/object:Gem::Dependency
127
+ name: pry
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
30
142
  description: Allows to describe field names that will be stored within hstore column
31
143
  together with their types. Data can then be retrieved with a set of helpful getters.
32
144
  email:
@@ -47,12 +159,11 @@ files:
47
159
  - lib/active_record/properties/base.rb
48
160
  - lib/active_record/properties/boolean_property.rb
49
161
  - lib/active_record/properties/counter_property.rb
50
- - lib/active_record/properties/extensions/booleans.rb
51
- - lib/active_record/properties/extensions/counters.rb
52
162
  - lib/active_record/properties/number_property.rb
53
163
  - lib/active_record/properties/string_property.rb
54
164
  - lib/activerecord-hstore_properties.rb
55
165
  - lib/activerecord-hstore_properties/version.rb
166
+ - spec/hstore_properties_spec.rb
56
167
  - spec/spec_helper.rb
57
168
  - test/test_helper.rb
58
169
  homepage: https://github.com/stevo/activerecord-hstore_properties
@@ -80,5 +191,6 @@ signing_key:
80
191
  specification_version: 3
81
192
  summary: Facilitate defining and retrieving information from hstore column
82
193
  test_files:
194
+ - spec/hstore_properties_spec.rb
83
195
  - spec/spec_helper.rb
84
196
  - test/test_helper.rb
@@ -1,15 +0,0 @@
1
- module ActiveRecord
2
- module Properties
3
- module Extensions
4
- module Booleans
5
- def method_missing(*args, &block)
6
- method_name = args.first.to_s
7
- defined, result = define_property_method(method_name, '_enabled?') do |property_name, object|
8
- ::ActiveRecord::ConnectionAdapters::Column.value_to_boolean(object.send("#{property_name}_property"))
9
- end
10
- defined ? result : super
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,28 +0,0 @@
1
- # Allows fetching properties as numerical values by adding _count suffix
2
-
3
- module ActiveRecord
4
- module Properties
5
- module Extensions
6
- module Counters
7
- def method_missing(*args, &block)
8
- method_name = args.first.to_s
9
-
10
- defined, result = if method_name.ends_with?('_bump!')
11
- define_property_method(method_name, '_bump!') do |property_name, object|
12
- _properties = object.properties
13
- _properties[property_name] = object.send("#{property_name}_count") + 1
14
- object.update_column(:properties, ActiveRecord::Coders::Hstore.new({}).dump(_properties))
15
- _properties[property_name]
16
- end
17
- else
18
- define_property_method(method_name, '_count') do |property_name, object|
19
- object.send("#{property_name}_property").to_i
20
- end
21
- end
22
-
23
- defined ? result : super
24
- end
25
- end
26
- end
27
- end
28
- end