activerecord-hstore_properties 0.0.3 → 0.0.4

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.
@@ -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