activerecord-hstore_properties 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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
-