property_sets 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md DELETED
@@ -1,145 +0,0 @@
1
- # Property sets [![Build Status](https://secure.travis-ci.org/zendesk/property_sets.png)](http://travis-ci.org/zendesk/property_sets)
2
-
3
- This gem is a way for you to use a basic "key/value" store for storing attributes for a given model in a relational fashion where there's a row per attribute. Alternatively you'd need to add a new column per attribute to your main table, or serialize the attributes and their values using the [ActiveRecord 3.2 store](https://github.com/rails/rails/commit/85b64f98d100d37b3a232c315daa10fad37dccdc).
4
-
5
- ## Description
6
-
7
- You configure the allowed stored properties by specifying these in the model:
8
-
9
- ```ruby
10
- class Account < ActiveRecord::Base
11
- property_set :settings do
12
- property :version, :default => "v1.0"
13
- property :featured, :protected => true
14
- property :activated
15
- end
16
-
17
- property_set :texts do
18
- property :epilogue
19
- end
20
- end
21
- ```
22
-
23
- The declared properties can then be accessed runtime via the defined association:
24
-
25
- ```ruby
26
- # Return the value of the version record for this account, or the default value if not set
27
- account.settings.version
28
-
29
- # Update the version record with given value
30
- account.settings.version = "v1.1"
31
-
32
- # Query the truth value of the property
33
- account.settings.featured?
34
-
35
- # Short hand for setting one or more values
36
- account.settings.set(:version => "v1.2", :activated => true)
37
-
38
- # Short hand for getting a hash with pairs for each key argument
39
- account.settings.get([:version, :activated])
40
- ```
41
-
42
- ### Validations
43
-
44
- Property sets supports standard AR validations, although in a somewhat manual fashion.
45
-
46
- ```ruby
47
- class Account < ActiveRecord::Base
48
- property_set :settings do
49
- property :version, :default => "v1.0"
50
- property :featured, :protected => true
51
-
52
- validates_format_of :value, :with => /v\d+\.\d+/, :message => "of version is invalid",
53
- :if => Proc.new { |r| r.name.to_sym == :version }
54
- end
55
- end
56
- ```
57
-
58
- On `account.save` this will result in an error record being added. You can also inspect the
59
- setting record using `account.settings.version_record`
60
-
61
- ### Bulk operations
62
-
63
- Stored properties can also be updated with the update_attributes and update_attributes! methods by
64
- enabling nested attributes. Like this (from the test cases):
65
-
66
- ```ruby
67
- @account.texts_attributes = [
68
- { :name => "foo", :value => "1" },
69
- { :name => "bar", :value => "0" }
70
- ]
71
- ```
72
-
73
- And for existing records:
74
-
75
- ```ruby
76
- @account.update_attributes!(:texts_attributes => [
77
- { :id => @account.texts.foo.id, :name => "foo", :value => "0" },
78
- { :id => @account.texts.bar.id, :name => "bar", :value => "1" }
79
- ])
80
- ```
81
-
82
- Using nested attributes is subject to implementing your own security measures for mass update assignments.
83
- Alternatively, it is possible to use a custom hash structure:
84
-
85
- ```ruby
86
- params = {
87
- :settings => { :version => "v4.0", :featured => "1" },
88
- :texts => { :epilogue => "Wibble wobble" }
89
- }
90
-
91
- @account.update_attributes(params)
92
- ```
93
-
94
- The above will not update `featured` as this has the protected flag set and is hence protected from
95
- mass updates.
96
-
97
- ### View helpers
98
-
99
- We support a couple of convenience mechanisms for building forms and putting the values into the above hash structure. So far, only support check boxes and radio buttons:
100
-
101
- ```erb
102
- <% form_for(:account, :html => { :method => :put }) do |f| %>
103
- <h3><%= f.property_set(:settings).check_box :activated %> Activated?</h3>
104
- <h3><%= f.property_set(:settings).radio_button :hot, "yes" %> Hot</h3>
105
- <h3><%= f.property_set(:settings).radio_button :not, "no" %> Not</h3>
106
- <h3><%= f.property_set(:settings).select :level, [["One", 1], ["Two", 2]] %></h3>
107
- <% end %>
108
- ```
109
-
110
- ## Installation
111
-
112
- Install the gem in your rails project by putting it in your Gemfile:
113
-
114
- ```
115
- gem "property_sets"
116
- ```
117
-
118
- Also remember to create the storage table(s), if for example you are going to be using this with an accounts model and a "settings" property set, you can define the table like:
119
-
120
- ```ruby
121
- create_table :account_settings do |t|
122
- t.integer :account_id, :null => false
123
- t.string :name, :null => false
124
- t.string :value
125
- t.timestamps
126
- end
127
-
128
- add_index :account_settings, [ :account_id, :name ], :unique => true
129
- ```
130
-
131
- ## Requirements
132
-
133
- * ActiveRecord
134
- * ActiveSupport
135
-
136
- ## License and copyright
137
-
138
- Copyright 2013 Zendesk
139
-
140
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
141
- You may obtain a copy of the License at
142
-
143
- http://www.apache.org/licenses/LICENSE-2.0
144
-
145
- Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
data/Rakefile DELETED
@@ -1,14 +0,0 @@
1
- require 'bundler/setup'
2
- require 'bundler/gem_tasks'
3
- require 'appraisal'
4
- require 'bump/tasks'
5
-
6
- require 'rake/testtask'
7
- Rake::TestTask.new do |test|
8
- test.pattern = 'test/**/test_*.rb'
9
- test.verbose = true
10
- end
11
-
12
- task :default do
13
- sh "bundle exec rake appraisal:install && bundle exec rake appraisal test"
14
- end
data/benchmark/read.rb DELETED
@@ -1,82 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test/helper')
2
-
3
- class Account < ActiveRecord::Base
4
- # Benchmark reading from an object with many settings when:
5
- # 1. Settings are undefined and use the default value (empty)
6
- # 2. Settings are defined and use the database value (fully defined)
7
-
8
- # This is a fairly realastic example of an object that has a lot of settings
9
- property_set :benchmark_settings do
10
- # 30 simple objects
11
- 10.times do |i|
12
- property "float_prop_#{i}", :type => :float, :default => 3.1415
13
- property "int_prop_#{i}", :type => :integer, :default => 22
14
- property "string_prop_#{i}", :type => :string, :default => "Sausalito, CA"
15
- end
16
-
17
- # 10 complex
18
- 5.times do |i|
19
- property "datetime_prop_#{i}", :type => :datetime, :default => Time.now.to_s
20
- property "serialized_prop_#{i}", :type => :serialized, :default => { "Hello" => "There" }
21
- end
22
-
23
- # 60 booleans
24
- 60.times do |i|
25
- property "boolean_prop_#{i}", :type => :boolean, :default => true
26
- end
27
- end
28
-
29
- end
30
-
31
- class BenchmarkRead < ActiveSupport::TestCase
32
-
33
- context "property sets" do
34
-
35
- setup do
36
- @account = Account.create(:name => "Name")
37
- end
38
-
39
- should "benchmark fully defined settings" do
40
- # Most settings are defined and will come from the database
41
- @account.benchmark_settings.keys.each do |key|
42
- @account.benchmark_settings.build_default(key)
43
- end
44
- @account.save!
45
- @account.reload
46
- assert_equal 100, @account.benchmark_settings.count
47
-
48
- GC.start
49
- full_timing = Benchmark.ms do
50
- 1_000.times do
51
- read_settings(@account)
52
- end
53
- end
54
- puts "Reading fully defined settings: #{full_timing}ms"
55
- end
56
-
57
- should "benchmark defaults" do
58
- assert_equal 0, @account.benchmark_settings.count
59
- # Most settings are undefined and will use the default value
60
- GC.start
61
- empty_timing = Benchmark.ms do
62
- 1_000.times do
63
- read_settings(@account)
64
- end
65
- end
66
- puts "Reading empty settings: #{empty_timing}ms"
67
- end
68
-
69
- end
70
-
71
- def read_settings(account)
72
- account.benchmark_settings.float_prop_1
73
- account.benchmark_settings.int_prop_1
74
- account.benchmark_settings.string_prop_1
75
- account.benchmark_settings.datetime_prop_1
76
- account.benchmark_settings.boolean_prop_20?
77
- account.benchmark_settings.boolean_prop_30?
78
- account.benchmark_settings.boolean_prop_40?
79
- account.benchmark_settings.boolean_prop_50?
80
- end
81
-
82
- end
@@ -1,20 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord-jdbcmysql-adapter", "1.3.5", :platforms=>:jruby
6
- gem "bump"
7
- gem "rake"
8
- gem "bundler"
9
- gem "appraisal"
10
- gem "actionpack", ">= 2.3.14", "< 4.1"
11
- gem "iconv", :platforms=>:ruby_20
12
- gem "activerecord", "~> 2.3.14"
13
- gem "activesupport", "~> 2.3.14"
14
- gem "shoulda", "~> 2.11"
15
- gem "mysql2", "~> 0.2.0", :platforms=>:ruby
16
- gem "activerecord-mysql2-adapter", :platforms=>:ruby
17
- gem "mocha", "~> 0.12.0"
18
- gem "test-unit", "< 2.5.5"
19
-
20
- gemspec :path=>"../"
@@ -1,19 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord-jdbcmysql-adapter", "1.3.5", :platforms=>:jruby
6
- gem "mysql2", :platforms=>:ruby
7
- gem "bump"
8
- gem "rake"
9
- gem "bundler"
10
- gem "shoulda"
11
- gem "mocha"
12
- gem "appraisal"
13
- gem "test-unit", ">= 2.5.2"
14
- gem "actionpack", ">= 2.3.14", "< 4.1"
15
- gem "iconv", :platforms=>:ruby_20
16
- gem "activerecord", "~> 3.2.6"
17
- gem "activesupport", "~> 3.2.6"
18
-
19
- gemspec :path=>"../"
@@ -1,20 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord-jdbcmysql-adapter", "1.3.5", :platforms=>:jruby
6
- gem "mysql2", :platforms=>:ruby
7
- gem "bump"
8
- gem "rake"
9
- gem "bundler"
10
- gem "shoulda"
11
- gem "mocha"
12
- gem "appraisal"
13
- gem "test-unit", ">= 2.5.2"
14
- gem "actionpack", ">= 2.3.14", "< 4.1"
15
- gem "iconv", :platforms=>:ruby_20
16
- gem "activerecord", "~> 4.0.2"
17
- gem "activesupport", "~> 4.0.2"
18
- gem "protected_attributes"
19
-
20
- gemspec :path=>"../"
@@ -1,20 +0,0 @@
1
- lib = File.expand_path("../lib/", __FILE__)
2
- $:.unshift lib unless $:.include?(lib)
3
-
4
- require 'property_sets/version'
5
-
6
- Gem::Specification.new "property_sets", PropertySets::VERSION do |s|
7
- s.summary = "Property sets for ActiveRecord."
8
- s.description = "This gem is an ActiveRecord extension which provides a convenient interface for managing per row properties."
9
- s.authors = ["Morten Primdahl"]
10
- s.email = 'primdahl@me.com'
11
- s.homepage = 'http://github.com/zendesk/property_sets'
12
- s.license = 'Apache License Version 2.0'
13
-
14
- s.add_runtime_dependency("activesupport", ">= 2.3.14", "< 4.1")
15
- s.add_runtime_dependency("activerecord", ">= 2.3.14", "< 4.1")
16
- s.add_runtime_dependency("json")
17
-
18
- s.files = `git ls-files`.split("\n")
19
- s.license = "MIT"
20
- end
data/test/database.rb DELETED
@@ -1,83 +0,0 @@
1
- # setup database
2
- require 'active_record'
3
- ActiveRecord::Base.logger = Logger.new(STDOUT)
4
- ActiveRecord::Base.logger.level = Logger::ERROR
5
-
6
- config = {
7
- :adapter => RUBY_PLATFORM == "java" ? 'mysql' : 'mysql2',
8
- :database => 'property_sets_test',
9
- :username => 'root',
10
- :password => nil,
11
- :host => '127.0.0.1',
12
- :port => 3306
13
- }
14
-
15
- ActiveRecord::Base.establish_connection(config.merge(:database => nil))
16
-
17
- # clear out everything
18
- ActiveRecord::Base.connection.drop_database config[:database]
19
- ActiveRecord::Base.connection.create_database config[:database], :charset => 'utf8', :collation => 'utf8_unicode_ci'
20
-
21
- # connect and check
22
- ActiveRecord::Base.establish_connection(config)
23
- ActiveRecord::Base.connection.execute('select 1')
24
-
25
- ActiveRecord::Migration.verbose = false
26
-
27
- ActiveRecord::Schema.define(:version => 1) do
28
- create_table "account_settings", :force => true do |t|
29
- t.integer "account_id"
30
- t.string "name"
31
- t.string "value"
32
- t.datetime "created_at"
33
- t.datetime "updated_at"
34
- end
35
-
36
- add_index :account_settings, [ :account_id, :name ], :unique => true
37
-
38
- create_table "account_texts", :force => true do |t|
39
- t.integer "account_id"
40
- t.string "name"
41
- t.string "value"
42
- t.datetime "created_at"
43
- t.datetime "updated_at"
44
- end
45
-
46
- add_index :account_texts, [ :account_id, :name ], :unique => true
47
-
48
- create_table "account_validations", :force => true do |t|
49
- t.integer "account_id"
50
- t.string "name"
51
- t.string "value"
52
- t.datetime "created_at"
53
- t.datetime "updated_at"
54
- end
55
-
56
- add_index :account_validations, [ :account_id, :name ], :unique => true
57
-
58
- create_table "account_typed_data", :force => true do |t|
59
- t.integer "account_id"
60
- t.string "name"
61
- t.string "value"
62
- t.datetime "created_at"
63
- t.datetime "updated_at"
64
- end
65
-
66
- add_index :account_typed_data, [ :account_id, :name ], :unique => true
67
-
68
- create_table "account_benchmark_settings", :force => true do |t|
69
- t.integer "account_id"
70
- t.string "name"
71
- t.string "value"
72
- t.datetime "created_at"
73
- t.datetime "updated_at"
74
- end
75
-
76
- add_index :account_benchmark_settings, [ :account_id, :name ], :unique => true
77
-
78
- create_table "accounts", :force => true do |t|
79
- t.string "name"
80
- t.datetime "created_at"
81
- t.datetime "updated_at"
82
- end
83
- end
@@ -1,14 +0,0 @@
1
- account1_foo:
2
- account_id: 1
3
- name: foo
4
- value:
5
-
6
- account1_bar:
7
- account_id: 1
8
- name: bar
9
- value: 1
10
-
11
- account1_baz:
12
- account_id: 1
13
- name: baz
14
- value: 0
@@ -1,4 +0,0 @@
1
- account1_foo:
2
- account_id: 1
3
- name: foo
4
- value:
@@ -1,3 +0,0 @@
1
- account1:
2
- name: The Account
3
- id: 1
data/test/helper.rb DELETED
@@ -1,99 +0,0 @@
1
- require 'rubygems'
2
- require 'bundler'
3
- Bundler.setup
4
-
5
- require 'test/unit'
6
-
7
- begin
8
- require 'mocha/setup' # Rails 2
9
- rescue LoadError
10
- require 'mocha'
11
- end
12
-
13
- require 'active_support'
14
- require 'active_support/core_ext'
15
- require 'active_record'
16
- require 'active_record/fixtures'
17
- require 'shoulda'
18
-
19
- if ActiveRecord::VERSION::MAJOR > 2
20
- if ActiveRecord::VERSION::MINOR > 1
21
- ActiveRecord::Base.mass_assignment_sanitizer = :strict
22
- end
23
- if ActiveRecord::VERSION::MAJOR == 4
24
- require 'protected_attributes'
25
- end
26
- ActiveRecord::Base.attr_accessible
27
- end
28
-
29
- I18n.enforce_available_locales = false if ActiveRecord::VERSION::MAJOR > 2
30
-
31
- require File.expand_path "../database", __FILE__
32
-
33
- $LOAD_PATH.unshift(File.dirname(__FILE__))
34
- require 'property_sets'
35
- require 'property_sets/delegator'
36
-
37
- class ActiveSupport::TestCase
38
- include ActiveRecord::TestFixtures
39
-
40
- def create_fixtures(*table_names)
41
- if block_given?
42
- Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
43
- else
44
- Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
45
- end
46
- end
47
-
48
- self.use_transactional_fixtures = true
49
- self.use_instantiated_fixtures = false
50
- end
51
-
52
- ActiveSupport::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
53
- $LOAD_PATH.unshift(ActiveSupport::TestCase.fixture_path)
54
-
55
- class ActsLikeAnInteger
56
- def to_i
57
- 123
58
- end
59
- end
60
-
61
- class Account < ActiveRecord::Base
62
- include PropertySets::Delegator
63
- delegate_to_property_set :settings, :old => :hep
64
-
65
- attr_accessible :name
66
- attr_accessible :texts_attributes
67
-
68
- property_set :settings do
69
- property :foo
70
- property :bar
71
- property :baz
72
- property :hep, :default => 'skep'
73
- property :pro, :protected => true
74
- end
75
-
76
- property_set :texts do
77
- property :foo
78
- property :bar
79
- end
80
-
81
- accepts_nested_attributes_for :texts
82
-
83
- property_set :validations do
84
- property :validated
85
- property :regular
86
-
87
- validates_format_of :value, :with => /\d+/, :message => "BEEP", :if => lambda { |r| r.name.to_sym == :validated }
88
- end
89
-
90
- property_set :typed_data do
91
- property :string_prop, :type => :string
92
- property :datetime_prop, :type => :datetime
93
- property :float_prop, :type => :float
94
- property :int_prop, :type => :integer
95
- property :serialized_prop, :type => :serialized
96
- property :default_prop, :type => :integer, :default => ActsLikeAnInteger.new
97
- property :serialized_prop_with_default, :type => :serialized, :default => "[]"
98
- end
99
- end