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.
- data/activerecord-hstore_properties.gemspec +11 -1
- data/lib/active_record/hstore_properties.rb +21 -22
- data/lib/active_record/properties/base.rb +17 -0
- data/lib/active_record/properties/boolean_property.rb +18 -0
- data/lib/active_record/properties/counter_property.rb +13 -1
- data/lib/activerecord-hstore_properties/version.rb +1 -1
- data/spec/hstore_properties_spec.rb +101 -0
- data/spec/spec_helper.rb +14 -1
- metadata +116 -4
- data/lib/active_record/properties/extensions/booleans.rb +0 -15
- data/lib/active_record/properties/extensions/counters.rb +0 -28
@@ -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
|
-
|
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
|
@@ -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.
|
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-
|
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
|