activerecord-hstore_properties 0.0.4 → 0.0.5

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/README.md ADDED
@@ -0,0 +1,157 @@
1
+ hstore-properties
2
+ =================
3
+
4
+ Setup
5
+ -----
6
+
7
+ Simply add following to your gemfile
8
+
9
+ `gem 'hstore-properties'`
10
+
11
+ Create `properties` column in the model you would like to use properties within, i.e.
12
+
13
+ `rails g migration AddPropertiesToUsers properties:hstore`
14
+
15
+ Apply your migration
16
+
17
+ `rake db:migrate`
18
+
19
+ Finally, describe your properties in your model file
20
+
21
+ ```ruby
22
+ class User < ActiveRecord::Base
23
+ include ActiveRecord::HstoreProperties
24
+ properties 'third_name',
25
+ 'some_cool_feature' => :boolean,
26
+ 'comments' => :counter,
27
+ 'age' => :number
28
+ end
29
+ ```
30
+
31
+ Usage
32
+ -----
33
+
34
+ ### Retrieving values
35
+
36
+ By default, all your properties are of type String. There are number of other property types available though...
37
+
38
+ * string
39
+ * boolean
40
+ * number
41
+ * counter
42
+ * translation
43
+
44
+ More will come in near future...
45
+
46
+ All properties can be retrieved just as they are written into hstore column, by suffixing them with `_property`, i.e.
47
+
48
+ ```ruby
49
+ User.last.third_name_property #=> "Jack"
50
+ ```
51
+
52
+ #### Booleans
53
+
54
+ *Boolean* properties, can be additionaly retrieved by using `_enabled?` and `?` suffixes, that will cast them to boolean value, i.e.
55
+
56
+ ```ruby
57
+ User.last.some_cool_feature_enabled? #=> true
58
+ User.last.some_cool_feature? #=> true
59
+ ```
60
+
61
+ What is more, you can toggle value of boolean property using `_enable!` / `_raise!` and `_disable!` / `_lower!` suffixes, e.g.
62
+
63
+ ```ruby
64
+ User.last.some_cool_feature_enable! #=> Changes property to true
65
+ User.last.some_cool_feature_raise! #=> Changes property to true
66
+ User.last.some_cool_feature_disable! #=> Changes property to false
67
+ User.last.some_cool_feature_lower! #=> Changes property to false
68
+ ```
69
+
70
+ #### Counters
71
+
72
+ *Counter* properties, can be retrieved by using `_count` suffix, that will cast them to integer value, i.e.
73
+
74
+ ```ruby
75
+ User.last.comments_count #=> 10
76
+ ```
77
+
78
+ What is more, it is possible to bump counter properties, i.e. following line will increment comments property by 1
79
+
80
+ ```ruby
81
+ User.last.comments_bump!
82
+ ```
83
+
84
+ #### Translations
85
+
86
+ *Translation* kind of property allows you to store translated strings in properties column.
87
+ The simplest way to store translation is just assign it a value, and it will save it in current locale, e.g.
88
+
89
+ ```ruby
90
+ class Category < ActiveRecord::Base
91
+ include ActiveRecord::HstoreProperties
92
+ properties 'caption' => :translation
93
+ end
94
+
95
+ c = Category.last
96
+ c.caption = "Nice product" #this will save 'Nice product' into caption_en property
97
+ c.save
98
+ c.caption #this will retrieve 'Nice product' from caption_en property
99
+ ```
100
+
101
+ You can always enforce in which locale you would like to store property, by suffixing it with any locale code available in `I18n.available_locales`
102
+
103
+ ```ruby
104
+ c = Category.last
105
+
106
+ c.caption_en = "Nice product"
107
+ c.caption_nb_no = "Fint produkt"
108
+
109
+ c.save
110
+
111
+ c.caption #=> "Nice product"
112
+ c.caption_nb_no #=> "Fint produkt"
113
+
114
+ I18n.locale = :'nb-NO'
115
+ c.caption #=> "Fint produkt"
116
+ ```
117
+
118
+ ### Updating through forms
119
+
120
+ You obviously need to add `:properties` to yours `attr_accessible`
121
+
122
+ Below is an example of building appropriate fields dynamically with formtastic
123
+
124
+
125
+ ```erb
126
+ <%= semantic_form_for @user do |f| %>
127
+ <%= f.first_name %>
128
+ <%= f.fields_for :properties, OpenStruct.new(@user.properties) do |builder| %>
129
+ <% User.properties.each do |property| %>
130
+ <%= builder.input property.name, property.formtastic_options %>
131
+ <% end %>
132
+ <% end %>
133
+ <%= f.submit %>
134
+ <% end %>
135
+ ```
136
+
137
+ Further customization
138
+ ---------------------
139
+
140
+ If most of your properties are of the same type, but other than string, you can overwrite `default_property_klass` to make other type default, i.e.
141
+
142
+ ```ruby
143
+ class User < ActiveRecord::Base
144
+ #...
145
+ def self.default_property_klass
146
+ ActiveRecord::Properties::BooleanProperty
147
+ end
148
+ end
149
+ ```
150
+
151
+ When to use?
152
+ ------------
153
+
154
+ * If you consider adding redundant column to your table, that will only sometimes store any data
155
+ * If you would like to make particular model "configurable"
156
+ * If you will not likely perform queries on specific field but mostly read from it directly
157
+
@@ -1,10 +1,12 @@
1
1
  require 'active_support/core_ext/class'
2
2
  require 'active_support/concern'
3
3
  require "active_record/properties/base"
4
+ require "active_record/properties/common_accessors"
4
5
  require "active_record/properties/boolean_property"
5
6
  require "active_record/properties/counter_property"
6
7
  require "active_record/properties/number_property"
7
8
  require "active_record/properties/string_property"
9
+ require "active_record/properties/translation_property"
8
10
 
9
11
  module ActiveRecord
10
12
  module HstoreProperties
@@ -50,8 +52,8 @@ module ActiveRecord
50
52
  primary_method_name = method_names.shift
51
53
 
52
54
  #Define main method once...
53
- define_method(primary_method_name) do
54
- self.instance_exec(property, &proc)
55
+ define_method(primary_method_name) do |*args|
56
+ self.instance_exec(property, *args, &proc)
55
57
  end
56
58
 
57
59
  #... and then define aliases
@@ -13,11 +13,6 @@ module ActiveRecord
13
13
  self._property_accessors = _property_accessors.merge(suffixes.to_a => block)
14
14
  end
15
15
  end
16
-
17
- add_property_accessor '_property' do |property|
18
- properties[property.name.to_s]
19
- end
20
-
21
16
  end
22
17
  end
23
18
  end
@@ -1,6 +1,8 @@
1
1
  module ActiveRecord
2
2
  module Properties
3
3
  class BooleanProperty < Base
4
+ include ActiveRecord::Properties::CommonAccessors
5
+
4
6
  def formtastic_options
5
7
  {:as => :boolean, :checked_value => 'true', :unchecked_value => 'false'}
6
8
  end
@@ -0,0 +1,17 @@
1
+ module ActiveRecord
2
+ module Properties
3
+ module CommonAccessors
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ add_property_accessor '_property' do |property|
7
+ properties[property.name.to_s]
8
+ end
9
+
10
+ add_property_accessor '=' do |property, *args|
11
+ properties_will_change!
12
+ properties[property.name.to_s] = args.shift
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,6 +1,8 @@
1
1
  module ActiveRecord
2
2
  module Properties
3
3
  class CounterProperty < Base
4
+ include ActiveRecord::Properties::CommonAccessors
5
+
4
6
  def formtastic_options
5
7
  {:as => :number, :disabled => true}
6
8
  end
@@ -1,6 +1,8 @@
1
1
  module ActiveRecord
2
2
  module Properties
3
3
  class NumberProperty < Base
4
+ include ActiveRecord::Properties::CommonAccessors
5
+
4
6
  def formtastic_options
5
7
  {:as => :number}
6
8
  end
@@ -1,6 +1,8 @@
1
1
  module ActiveRecord
2
2
  module Properties
3
3
  class StringProperty < Base
4
+ include ActiveRecord::Properties::CommonAccessors
5
+
4
6
  def formtastic_options
5
7
  {:as => :string}
6
8
  end
@@ -0,0 +1,31 @@
1
+ module ActiveRecord
2
+ module Properties
3
+ class TranslationProperty < Base
4
+ def formtastic_options
5
+ {:as => :string}
6
+ end
7
+
8
+ add_property_accessor '=' do |property, *args|
9
+ property_name = "#{property.name.to_s}_#{I18n.locale.to_s.underscore}"
10
+ properties[property_name] = args.shift
11
+ end
12
+
13
+ add_property_accessor '_property' do |property|
14
+ property_name = "#{property.name.to_s}_#{I18n.locale.to_s.underscore}"
15
+ properties[property_name]
16
+ end
17
+
18
+ I18n.available_locales.each do |locale|
19
+ add_property_accessor "_#{locale.to_s.underscore}" do |property|
20
+ property_name = "#{property.name.to_s}_#{locale.to_s.underscore}"
21
+ properties[property_name]
22
+ end
23
+
24
+ add_property_accessor "_#{locale.to_s.underscore}=" do |property, *args|
25
+ property_name = "#{property.name.to_s}_#{locale.to_s.underscore}"
26
+ properties[property_name] = args.shift
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,5 +1,5 @@
1
1
  module Activerecord
2
2
  module HstoreProperties
3
- VERSION = "0.0.4"
3
+ VERSION = "0.0.5"
4
4
  end
5
5
  end
@@ -1,4 +1,6 @@
1
1
  require 'spec_helper'
2
+ require 'activerecord-hstore_properties'
3
+
2
4
  describe ActiveRecord::HstoreProperties do
3
5
  with_model :Comment do
4
6
  table do |t|
@@ -8,7 +10,6 @@ describe ActiveRecord::HstoreProperties do
8
10
 
9
11
  model do
10
12
  include ActiveRecord::HstoreProperties
11
-
12
13
  #We need to do that, as sqlite does not support hstore
13
14
  self.class_eval do
14
15
  def properties
@@ -18,11 +19,11 @@ describe ActiveRecord::HstoreProperties do
18
19
  end
19
20
  end
20
21
 
21
- it "it should respond to properties call" do
22
+ it "should respond to properties call" do
22
23
  Comment.respond_to?(:properties).should be_true
23
24
  end
24
25
 
25
- it "it should be possible to define properties" do
26
+ it "should be possible to define properties" do
26
27
  Comment.properties 'property_one', 'property_two'
27
28
  Comment.properties.should be_an_instance_of(Array)
28
29
  Comment.properties.map(&:name).should include('property_one', 'property_two')
@@ -33,7 +34,7 @@ describe ActiveRecord::HstoreProperties do
33
34
  Comment.properties.first.should be_a_kind_of(ActiveRecord::Properties::StringProperty)
34
35
  end
35
36
 
36
- it "it should be possible to define property types other than string" do
37
+ it "should be possible to define property types other than string" do
37
38
  Comment.properties 'property_one', 'property_two' => :boolean
38
39
  Comment.properties.find { |p| p.name == 'property_two' }.should be_a_kind_of(ActiveRecord::Properties::BooleanProperty)
39
40
  end
@@ -48,8 +49,16 @@ describe ActiveRecord::HstoreProperties do
48
49
 
49
50
  it "properties_set should not return underscored properties" do
50
51
  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
52
+ Comment.properties_set.find { |p| p.name == '_property_one' }.should be_nil
53
+ Comment.properties_set.find { |p| p.name == 'property_two' }.should_not be_nil
54
+ end
55
+
56
+ it "should be possible to assign property value using simple accessor" do
57
+ Comment.properties 'property_two' => :boolean
58
+ comment = Comment.new
59
+ comment.property_two = true
60
+ comment.save
61
+ comment.property_two_property.should == 'true'
53
62
  end
54
63
 
55
64
  context "boolean properties" do
@@ -92,10 +101,43 @@ describe ActiveRecord::HstoreProperties do
92
101
  it "should be possible to query for current count" do
93
102
  @comment.property_two_count.should == 0
94
103
  @comment.property_two_bump!
95
-
96
104
  @comment.property_two_count.should == 1
97
105
  end
106
+ end
98
107
 
108
+ context "translation properties" do
109
+ before(:each) do
110
+ Comment.properties 'property_two' => :translation
111
+ @comment = Comment.new
112
+ @comment.save
99
113
  end
100
114
 
115
+ it "assigning a value should store it in current language scope" do
116
+ I18n.locale = :'en-GB'
117
+ @comment.property_two = "nice"
118
+ @comment.save
119
+
120
+ @comment.properties['property_two_en_gb'].should == 'nice'
121
+ end
122
+
123
+ it "retrieving raw value should take current locale into account" do
124
+ I18n.locale = :'en-GB'
125
+ @comment.property_two = "nice"
126
+ @comment.save
127
+
128
+ I18n.locale = :'nb-NO'
129
+ @comment.property_two_property.should be_nil
130
+ I18n.locale = :'en-GB'
131
+ @comment.property_two_property.should == 'nice'
132
+ end
133
+
134
+ it "should be possible to use direct readers and writers for all available locales" do
135
+ @comment.property_two_nb_no = 'Norwegian'
136
+ @comment.property_two_pl = 'Polish'
137
+ @comment.save
138
+
139
+ @comment.property_two_nb_no.should == 'Norwegian'
140
+ @comment.property_two_pl.should == 'Polish'
141
+ end
142
+ end
101
143
  end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,11 @@
1
- require 'activerecord-hstore_properties'
2
1
  require 'with_model'
3
2
  require 'active_record'
4
3
  require 'activerecord-postgres-hstore'
5
4
  require 'pry'
6
5
 
6
+ #For later testing of translation properties
7
+ I18n.available_locales = [:"nb-NO", :"en-GB", :pl]
8
+
7
9
  RSpec.configure do |config|
8
10
  ActiveRecord::Base.establish_connection(
9
11
  :adapter => 'sqlite3',
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
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-11 00:00:00.000000000 Z
12
+ date: 2013-04-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -152,15 +152,17 @@ files:
152
152
  - Gemfile
153
153
  - LICENSE
154
154
  - LICENSE.txt
155
- - README.textile
155
+ - README.md
156
156
  - Rakefile
157
157
  - activerecord-hstore_properties.gemspec
158
158
  - lib/active_record/hstore_properties.rb
159
159
  - lib/active_record/properties/base.rb
160
160
  - lib/active_record/properties/boolean_property.rb
161
+ - lib/active_record/properties/common_accessors.rb
161
162
  - lib/active_record/properties/counter_property.rb
162
163
  - lib/active_record/properties/number_property.rb
163
164
  - lib/active_record/properties/string_property.rb
165
+ - lib/active_record/properties/translation_property.rb
164
166
  - lib/activerecord-hstore_properties.rb
165
167
  - lib/activerecord-hstore_properties/version.rb
166
168
  - spec/hstore_properties_spec.rb
data/README.textile DELETED
@@ -1,93 +0,0 @@
1
- h1. hstore-properties
2
-
3
-
4
- h2. Setup
5
-
6
-
7
- Simply add following to your gemfile
8
-
9
- @gem 'hstore-properties'@
10
-
11
- Create @properties@ column in the model you would like to use properties within, i.e.
12
-
13
- @rails g migration AddPropertiesToUsers properties:hstore@
14
-
15
- Apply your migration
16
-
17
- @rake db:migrate@
18
-
19
- Finally, describe your properties in your model file
20
-
21
- bc. class User < ActiveRecord::Base
22
- include ActiveRecord::HstoreProperties
23
- properties 'third_name',
24
- 'some_cool_feature' => :boolean,
25
- 'comments' => :counter,
26
- 'age' => :number
27
- end
28
-
29
-
30
- h2. Usage
31
-
32
- h3. Retrieving values
33
-
34
- By default, all your properties are of type String. There are number of other property types available though...
35
-
36
- * string
37
- * boolean
38
- * number
39
- * counter
40
-
41
- More will come in near future...
42
-
43
- All properties can be retrieved just as they are written into hstore column, by suffixing them with @_property@, i.e.
44
-
45
- @User.last.third_name_property #=> "Jack"@
46
-
47
- *Boolean* properties, can be additionaly retrieved by using @_enabled?@ suffix, that will cast them to boolean value, i.e.
48
-
49
- @User.last.some_cool_feature_enabled? #=> true@
50
-
51
- *Counter* properties, can be retrieved by using @_count@ suffix, that will cast them to integer value, i.e.
52
-
53
- @User.last.comments_count #=> 10@
54
-
55
- What is more, it is possible to bump counter properties, i.e. following line will increment comments property by 1
56
-
57
- @User.last.comments_bump!@
58
-
59
-
60
- h3. Updating through forms
61
-
62
- You obviously need to add @:properties@ to yours @attr_accessible@
63
-
64
- Below is an example of building appropriate fields dynamically with formtastic
65
-
66
- bc.. <%= semantic_form_for @user do |f| %>
67
- <%= f.first_name %>
68
- <%= f.fields_for :properties, OpenStruct.new(@user.properties) do |builder| %>
69
- <% User.properties.each do |property| %>
70
- <%= builder.input property.name, property.formtastic_options %>
71
- <% end %>
72
- <% end %>
73
- <%= f.submit %>
74
- <% end %>
75
-
76
- h2. Further customization
77
-
78
- If most of your properties are of the same type, but other than string, you can overwrite @default_property_klass@ to make other type default, i.e.
79
-
80
- bc.
81
- class User < ActiveRecord::Base
82
- #...
83
- def self.default_property_klass
84
- ActiveRecord::Properties::BooleanProperty
85
- end
86
- end
87
-
88
- h2. When to use?
89
-
90
- * If you consider adding redundant column to your table, that will only sometimes store any data
91
- * If you would like to make particular model "configurable"
92
- * If you will not likely perform queries on specific field but mostly read from it directly
93
-