simple_set 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +132 -0
- data/Rakefile +6 -0
- data/lib/simple_set/set_hash.rb +18 -0
- data/lib/simple_set/version.rb +3 -0
- data/lib/simple_set.rb +141 -0
- data/simple_set.gemspec +25 -0
- data/spec/simple_set_spec.rb +280 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/models.rb +23 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a89d5b1d434529dfd5e8496e9d3f6e276912068a
|
4
|
+
data.tar.gz: 431ecc28bbd8bf82a6ba765ab00e553ea6d77575
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 58858c8bf1379593972d5b39f9173dcfe463a3166646f798d4d17754b56649d64069e0049846681e44d920853ee7bfb07067558089ddc73234c9509e8245d308
|
7
|
+
data.tar.gz: b567de32fd5286e4730086673e495088a2463974fe3b45eaf71ab213fa48c8ce8080eddfe32a82f48bb277c02d3e6f20e88589b97bc9d196e950cc1145a3127b
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2010 Sven Fuchs <svenfuchs@artweb-design.de>
|
2
|
+
Copyright (c) 2014 Romain Tartière <romain@blogreen.org>
|
3
|
+
|
4
|
+
MIT License
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# SimpleSet
|
2
|
+
|
3
|
+
A Rails plugin which brings easy-to-use set-like functionality to ActiveRecord models.
|
4
|
+
|
5
|
+
This is based on [SimpleEnum](https://github.com/lwe/simple_enum).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'simple_set'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install simple_set
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Add this to a model:
|
24
|
+
|
25
|
+
class User < ActiveRecord::Base
|
26
|
+
as_set :roles, [:accounting, :management]
|
27
|
+
end
|
28
|
+
|
29
|
+
Then create the required `roles_cd` column using migrations:
|
30
|
+
|
31
|
+
class AddRolesToUsers < ActiveRecord::Migration
|
32
|
+
def change
|
33
|
+
add_column :users, :roles_cd, :integer
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Now, it's possible to manage roles with maximum ease:
|
38
|
+
|
39
|
+
bob = User.new
|
40
|
+
bob.roles = [:accounting]
|
41
|
+
bob.accounting? #=> true
|
42
|
+
bob.management? #=> false
|
43
|
+
bob.roles #=> [:accounting]
|
44
|
+
bob.roles_cd #=> 1
|
45
|
+
|
46
|
+
## Gotchas
|
47
|
+
|
48
|
+
1. Acceptable values can be provided as an `Array` or as a `Hash`, the
|
49
|
+
following lines are equivalent:
|
50
|
+
|
51
|
+
as_set :spoken_languages, [:english, :french, :german, :japanese]
|
52
|
+
as_set :spoken_languages, {english: 1, french: 2, german: 4, japanese: 8}
|
53
|
+
|
54
|
+
Reordering the array will change each element's value which is likely
|
55
|
+
unwanted. Either only append new elements to the `Array` notation or use
|
56
|
+
the `Hash` notation.
|
57
|
+
|
58
|
+
2. Although the `Hash` notation is less intuitive than the `Array` notation, it
|
59
|
+
allows some neat tricks:
|
60
|
+
|
61
|
+
class User
|
62
|
+
as_set :roles, {
|
63
|
+
management: 1,
|
64
|
+
accounting: 2,
|
65
|
+
human_resources: 4,
|
66
|
+
|
67
|
+
director: 7,
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
bob = User.create(roles: [:management, :accounting])
|
72
|
+
bob.director? #=> false
|
73
|
+
bob.human_resources = true
|
74
|
+
bob.director? #=> true
|
75
|
+
|
76
|
+
3. If the shortcut methods (like `<symbol>?`, `<symbol>=` or `Klass.<symbol>`)
|
77
|
+
conflict with something in your class, it’s possible to define a prefix:
|
78
|
+
|
79
|
+
class Lp < ActiveRecord::Base
|
80
|
+
as_set :media_conditions, [:new, :sealed, :very_good, :good, :fair, :poor], prefix: true
|
81
|
+
end
|
82
|
+
|
83
|
+
Bug.media_condition_new #=> 1
|
84
|
+
|
85
|
+
When `:prefix` is set to `true`, shortcut methods are prefixed by the
|
86
|
+
_singularized name_ of the attribute.
|
87
|
+
|
88
|
+
The `:prefix` option not only takes a boolean value as an argument, but
|
89
|
+
instead can also be supplied a custom prefix (i.e. any string or symbol), so
|
90
|
+
with `prefix: 'foo'` all shortcut methods would look like: `foo_<symbol>...`
|
91
|
+
|
92
|
+
4. Sometimes it might be useful to disable the generation of the shortcut
|
93
|
+
methods (`<symbol>?`, `<symbol>=` and `Klass.<symbol>`), to do so just add
|
94
|
+
the option `slim: true`:
|
95
|
+
|
96
|
+
class User
|
97
|
+
as_set :spoken_languages, [:english, :french, :german, :japanese], slim: true
|
98
|
+
end
|
99
|
+
|
100
|
+
bob = User.create(spoken_languages: [:english, :french]
|
101
|
+
bob.spoken_languages #=> [:english, :french]
|
102
|
+
bob.french? #=> throws NoMethodError: undefined method `french?'
|
103
|
+
bob.french = false #=> throws NoMethodError: undefined method `french='
|
104
|
+
User.french #=> throws NoMethodError: undefined method `french'
|
105
|
+
|
106
|
+
5. Easy Rails integration:
|
107
|
+
|
108
|
+
Given a `User` is declared as:
|
109
|
+
|
110
|
+
class User < ActiveRecord::Base
|
111
|
+
as_set :roles, [:management, :accounting, :human_resources]
|
112
|
+
end
|
113
|
+
|
114
|
+
Adjust strong parameters to allow roles assignment:
|
115
|
+
|
116
|
+
params.require(:user).permit(:roles => [])
|
117
|
+
|
118
|
+
And then render a collection of checkboxes:
|
119
|
+
|
120
|
+
= form_for @user do |f|
|
121
|
+
= f.collection_check_boxes(:roles, User.roles, :to_sym, :to_sym) do |b|
|
122
|
+
= b.check_box
|
123
|
+
= b.label do
|
124
|
+
= t("application.roles.#{b.text}")
|
125
|
+
|
126
|
+
## Contributing
|
127
|
+
|
128
|
+
1. Fork it
|
129
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
130
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
131
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
132
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'simple_enum/enum_hash'
|
2
|
+
|
3
|
+
module SimpleSet
|
4
|
+
class SetHash < ::SimpleEnum::EnumHash
|
5
|
+
def initialize(args = [], strings = false)
|
6
|
+
super()
|
7
|
+
|
8
|
+
if args.is_a?(Hash) then
|
9
|
+
args.each { |k,v| set_value_for_reverse_lookup(k, v) }
|
10
|
+
else
|
11
|
+
ary = args.send(args.respond_to?(:enum_with_index) ? :enum_with_index : :each_with_index).map { |x,y| [ x, 2**y ] } unless args.first.respond_to?(:map)
|
12
|
+
ary = args.map { |e| [e, 2**e.id] } if args.first.respond_to?(:map) && !args.first.is_a?(Array)
|
13
|
+
ary ||= args
|
14
|
+
ary.each { |e| set_value_for_reverse_lookup(e[0], strings ? e[0].to_s : e[1]) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/simple_set.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
|
4
|
+
require 'simple_set/version'
|
5
|
+
require 'simple_set/set_hash'
|
6
|
+
|
7
|
+
require 'active_support/deprecation'
|
8
|
+
|
9
|
+
module SimpleSet
|
10
|
+
class << self
|
11
|
+
def default_options
|
12
|
+
@default_options ||= {
|
13
|
+
whiny: true,
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def included(base)
|
18
|
+
base.send :class_attribute, :simple_set_definitions, instance_writer: false, instance_reader: false
|
19
|
+
base.send :extend, ClassMethods
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
# Provides ability to create simple sets based on hashes or arrays, backed
|
25
|
+
# by integer columns (but not limited to integer columns).
|
26
|
+
#
|
27
|
+
# Columns are supposed to be suffixed by <tt>_cd</tt>, if not, use
|
28
|
+
# <tt>:column => 'the_column_name'</tt>, so some example migrations:
|
29
|
+
#
|
30
|
+
# add_column :users, :roles_cd, :integer
|
31
|
+
# add_column :users, :permissions, :integer # and a custom column...
|
32
|
+
#
|
33
|
+
# and then in your model:
|
34
|
+
#
|
35
|
+
# class User
|
36
|
+
# as_set :roles, [:management, :accounting]
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# # or use a hash:
|
40
|
+
#
|
41
|
+
# class User
|
42
|
+
# as_set :user_permissions, { create_invoice: 1, send_invoice: 2, create_user: 4, all: 7 }, column: 'permissions'
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# Now it's possible to access the set and the internally stored value like:
|
46
|
+
#
|
47
|
+
# john_doe = User.new
|
48
|
+
# john_doe.roles #=> []
|
49
|
+
# john_doe.roles = [:accounting]
|
50
|
+
# john_doe.roles #=> [:accounting]
|
51
|
+
# john_doe.roles_cd #=> 2
|
52
|
+
#
|
53
|
+
# And to make life a tad easier: a few shortcut methods to work with the set are also created.
|
54
|
+
#
|
55
|
+
# john_doe.accounting? #=> true
|
56
|
+
# john_doe.accounting = false
|
57
|
+
# john_doe.accounting? #=> false
|
58
|
+
#
|
59
|
+
# === Configuration options:
|
60
|
+
# * <tt>:column</tt> - Specifies a custom column name, instead of the
|
61
|
+
# default suffixed <tt>_cd</tt> column.
|
62
|
+
# * <tt>:prefix</tt> - Define a prefix, which is prefixed to the shortcut
|
63
|
+
# methods (e.g. <tt><symbol>=</tt> and <tt><symbol>?</tt>), if it's set
|
64
|
+
# to <tt>true</tt> the enumeration name is used as a prefix, else a
|
65
|
+
# custom prefix (symbol or string) (default is <tt>nil</tt> => no prefix)
|
66
|
+
# * <tt>:slim</tt> - If set to <tt>true</tt> no shortcut methods for all
|
67
|
+
# enumeration values are being generated, if set to <tt>:class</tt> only
|
68
|
+
# class-level shortcut methods are disabled (default is <tt>nil</tt> =>
|
69
|
+
# they are generated)
|
70
|
+
# * <tt>:whiny</tt> - Boolean value which if set to <tt>true</tt> will
|
71
|
+
# throw an <tt>ArgumentError</tt> if an invalid value is passed to the
|
72
|
+
# setter (e.g. a value for which no enumeration exists). if set to
|
73
|
+
# <tt>false</tt> no exception is thrown and the internal value is left
|
74
|
+
# untouched (default is <tt>true</tt>)
|
75
|
+
def as_set(set_cd, values, options = {})
|
76
|
+
options = SimpleSet.default_options.merge({column: "#{set_cd}_cd"}).merge(options)
|
77
|
+
options.assert_valid_keys(:column, :prefix, :slim, :whiny)
|
78
|
+
|
79
|
+
metaclass = (class << self; self; end)
|
80
|
+
|
81
|
+
values = SimpleSet::SetHash.new(values)
|
82
|
+
|
83
|
+
define_method("#{set_cd}") do
|
84
|
+
current = send(options[:column])
|
85
|
+
return nil if current.nil?
|
86
|
+
values.select { |k,v| v == current & v }.keys
|
87
|
+
end
|
88
|
+
|
89
|
+
define_method("#{set_cd}=") do |new_values|
|
90
|
+
real = nil
|
91
|
+
if ! new_values.nil? then
|
92
|
+
new_values = new_values.reject { |x| x == ''}.collect { |x| x.to_sym }
|
93
|
+
real = new_values.collect do |k|
|
94
|
+
if values.has_key?(k) then
|
95
|
+
values[k]
|
96
|
+
else
|
97
|
+
raise(ArgumentError, "Invalid set value : #{k}") if options[:whiny]
|
98
|
+
0
|
99
|
+
end
|
100
|
+
end.inject(:|)
|
101
|
+
end
|
102
|
+
send("#{options[:column]}=", real)
|
103
|
+
end
|
104
|
+
|
105
|
+
metaclass.send :define_method, "#{set_cd}" do
|
106
|
+
return values.keys
|
107
|
+
end
|
108
|
+
|
109
|
+
if options[:slim] != true then
|
110
|
+
prefix = options[:prefix] && "#{options[:prefix] == true ? set_cd.to_s.singularize : options[:prefix]}_"
|
111
|
+
values.each do |k,code|
|
112
|
+
sym = SetHash.symbolize(k)
|
113
|
+
|
114
|
+
define_method("#{prefix}#{sym}?") do
|
115
|
+
current = send(options[:column]) || 0
|
116
|
+
code == (code & current)
|
117
|
+
end
|
118
|
+
|
119
|
+
define_method("#{prefix}#{sym}=") do |value|
|
120
|
+
current = send(options[:column]) || 0
|
121
|
+
if value then
|
122
|
+
current |= code
|
123
|
+
else
|
124
|
+
current &= ~code
|
125
|
+
end
|
126
|
+
send("#{options[:column]}=", current)
|
127
|
+
code == (current & code)
|
128
|
+
end
|
129
|
+
|
130
|
+
unless options[:slim] == :class then
|
131
|
+
metaclass.send(:define_method, "#{prefix}#{sym}", Proc.new { |*args| args.first ? k : code })
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
ActiveSupport.on_load(:active_record) do
|
140
|
+
ActiveRecord::Base.send(:include, SimpleSet)
|
141
|
+
end
|
data/simple_set.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'simple_set/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "simple_set"
|
8
|
+
spec.version = SimpleSet::VERSION
|
9
|
+
spec.authors = ["Romain Tartière"]
|
10
|
+
spec.email = ["romain@blogreen.org"]
|
11
|
+
spec.summary = %q{Simple set-like field support for ActiveModel}
|
12
|
+
spec.homepage = "https://github.com/smortex/simple_set"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "simple_enum", "~> 1.6.8"
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SimpleSet do
|
4
|
+
it 'should raise on error when manipulating invalid values' do
|
5
|
+
named_model('TestExceptions') do
|
6
|
+
as_set :values, [:a, :b]
|
7
|
+
end
|
8
|
+
|
9
|
+
sample = TestExceptions.new
|
10
|
+
expect { sample.values = [:a] }.to_not raise_error
|
11
|
+
expect { sample.values = [:b] }.to_not raise_error
|
12
|
+
expect { sample.values = [:c] }.to raise_error(ArgumentError)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should accept an array of symbols' do
|
16
|
+
named_model('InitWithArrayOfSymbol') do
|
17
|
+
as_set :values, [:a, :b, :c, :d, :e, :f]
|
18
|
+
end
|
19
|
+
|
20
|
+
InitWithArrayOfSymbol.a.should == 1
|
21
|
+
InitWithArrayOfSymbol.b.should == 2
|
22
|
+
InitWithArrayOfSymbol.c.should == 4
|
23
|
+
InitWithArrayOfSymbol.d.should == 8
|
24
|
+
InitWithArrayOfSymbol.e.should == 16
|
25
|
+
InitWithArrayOfSymbol.f.should == 32
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should accept a hash' do
|
29
|
+
named_model('InitWithHash') do
|
30
|
+
as_set :values, { a: 1, b: 2, c: 4, d: 8, all: 15 }
|
31
|
+
end
|
32
|
+
|
33
|
+
InitWithHash.a.should == 1
|
34
|
+
InitWithHash.b.should == 2
|
35
|
+
InitWithHash.c.should == 4
|
36
|
+
InitWithHash.d.should == 8
|
37
|
+
InitWithHash.all.should == 15
|
38
|
+
|
39
|
+
sample = InitWithHash.new
|
40
|
+
sample.all = true
|
41
|
+
sample.a?.should be_true
|
42
|
+
sample.b?.should be_true
|
43
|
+
sample.c?.should be_true
|
44
|
+
sample.d?.should be_true
|
45
|
+
sample.all?.should be_true
|
46
|
+
sample.b = false
|
47
|
+
sample.all?.should be_false
|
48
|
+
sample.b = true
|
49
|
+
sample.all?.should be_true
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should distinguish nil from empty set' do
|
53
|
+
named_model('NilOrEmpty') do
|
54
|
+
as_set :values, [:a, :b]
|
55
|
+
end
|
56
|
+
|
57
|
+
sample = NilOrEmpty.new
|
58
|
+
|
59
|
+
sample.a?.should be_false
|
60
|
+
sample.b?.should be_false
|
61
|
+
sample.values_cd.should == nil
|
62
|
+
sample.values.should == nil
|
63
|
+
|
64
|
+
sample.values = [:a]
|
65
|
+
sample.values.should == [:a]
|
66
|
+
sample.values = nil
|
67
|
+
sample.values.should == nil
|
68
|
+
|
69
|
+
sample.a = true
|
70
|
+
sample.values.should == [:a]
|
71
|
+
sample.a = false
|
72
|
+
sample.values.should == []
|
73
|
+
|
74
|
+
sample.values = nil
|
75
|
+
sample.values.should == nil
|
76
|
+
sample.a = false
|
77
|
+
sample.values.should == []
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should support fields with a default value' do
|
81
|
+
named_model('FieldWithDefaultValue') do
|
82
|
+
as_set :values_with_default, [:x, :y]
|
83
|
+
end
|
84
|
+
|
85
|
+
sample = FieldWithDefaultValue.new
|
86
|
+
sample.values_with_default_cd.should == 2
|
87
|
+
sample.values_with_default.should == [:y]
|
88
|
+
|
89
|
+
sample.values_with_default = nil
|
90
|
+
sample.values_with_default.should == nil
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should work outside activerecord' do
|
94
|
+
class FruitsEater
|
95
|
+
include SimpleSet
|
96
|
+
as_set :fruits_i_like, [:apples, :bananas, :pinaple]
|
97
|
+
attr_accessor :fruits_i_like_cd
|
98
|
+
end
|
99
|
+
|
100
|
+
sample = FruitsEater.new
|
101
|
+
sample.fruits_i_like = [:apples, :pinaple]
|
102
|
+
sample.fruits_i_like_cd.should == 5
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should return acceptable values' do
|
106
|
+
named_model('AcceptableValues') do
|
107
|
+
as_set :spoken_languages, [:english, :french, :german, :japanese]
|
108
|
+
end
|
109
|
+
|
110
|
+
AcceptableValues.spoken_languages.should == [:english, :french, :german, :japanese]
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should support Rails assignment' do
|
114
|
+
named_model('User') do
|
115
|
+
as_set :values, [:foo_manager, :bar_manager, :baz_manager]
|
116
|
+
end
|
117
|
+
|
118
|
+
sample = User.new
|
119
|
+
sample.values = ["foo_manager", "baz_manager", ""]
|
120
|
+
sample.values.should == [:foo_manager, :baz_manager]
|
121
|
+
end
|
122
|
+
|
123
|
+
# ___ _ _
|
124
|
+
# / _ \ _ __ | |_(_) ___ _ __ ___
|
125
|
+
# | | | | '_ \| __| |/ _ \| '_ \/ __|
|
126
|
+
# | |_| | |_) | |_| | (_) | | | \__ \
|
127
|
+
# \___/| .__/ \__|_|\___/|_| |_|___/
|
128
|
+
# |_|
|
129
|
+
|
130
|
+
describe 'options' do
|
131
|
+
|
132
|
+
# _ _
|
133
|
+
# (_)__ ___| |_ _ _ __ _ _
|
134
|
+
# _/ _/ _ \ | || | ' \| ' \
|
135
|
+
# (_)__\___/_|\_,_|_|_|_|_||_|
|
136
|
+
#
|
137
|
+
|
138
|
+
describe ":column" do
|
139
|
+
it 'should support a custom column name' do
|
140
|
+
named_model('TestOptionColumn1') do
|
141
|
+
as_set :languages, [:english, :french, :german, :japanese], column: 'custom_name'
|
142
|
+
end
|
143
|
+
|
144
|
+
sample = TestOptionColumn1.new
|
145
|
+
sample.languages = [:french, :german]
|
146
|
+
sample.english?.should be_false
|
147
|
+
sample.french?.should be_true
|
148
|
+
sample.german?.should be_true
|
149
|
+
sample.japanese?.should be_false
|
150
|
+
sample.custom_name.should == 6
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# _ __ _
|
155
|
+
# (_)_ __ _ _ ___ / _(_)_ __
|
156
|
+
# _| '_ \ '_/ -_) _| \ \ /
|
157
|
+
# (_) .__/_| \___|_| |_/_\_\
|
158
|
+
# |_|
|
159
|
+
|
160
|
+
describe ':prefix' do
|
161
|
+
it "should support automatic prefix in getters and setters" do
|
162
|
+
named_model('TestOptionPrefix1') do
|
163
|
+
as_set :spoken_languages, [:english, :french, :german, :japanese], prefix: true
|
164
|
+
end
|
165
|
+
|
166
|
+
sample = TestOptionPrefix1.new
|
167
|
+
sample.should respond_to(:spoken_language_english?)
|
168
|
+
sample.should respond_to(:spoken_language_french?)
|
169
|
+
sample.should respond_to(:spoken_language_german?)
|
170
|
+
sample.should respond_to(:spoken_language_japanese?)
|
171
|
+
|
172
|
+
sample.should respond_to(:spoken_language_english=)
|
173
|
+
sample.should respond_to(:spoken_language_french=)
|
174
|
+
sample.should respond_to(:spoken_language_german=)
|
175
|
+
sample.should respond_to(:spoken_language_japanese=)
|
176
|
+
|
177
|
+
TestOptionPrefix1.should respond_to(:spoken_language_english)
|
178
|
+
TestOptionPrefix1.should respond_to(:spoken_language_french)
|
179
|
+
TestOptionPrefix1.should respond_to(:spoken_language_german)
|
180
|
+
TestOptionPrefix1.should respond_to(:spoken_language_japanese)
|
181
|
+
|
182
|
+
sample.should_not respond_to(:japanese?)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should support custom prefix in getters and setters" do
|
186
|
+
named_model('TestOptionPrefix2') do
|
187
|
+
as_set :spoken_languages, [:english, :french, :german, :japanese], prefix: 'speaks'
|
188
|
+
end
|
189
|
+
|
190
|
+
sample = TestOptionPrefix2.new
|
191
|
+
sample.should respond_to(:speaks_english?)
|
192
|
+
sample.should respond_to(:speaks_french?)
|
193
|
+
sample.should respond_to(:speaks_german?)
|
194
|
+
sample.should respond_to(:speaks_japanese?)
|
195
|
+
|
196
|
+
sample.should respond_to(:speaks_english=)
|
197
|
+
sample.should respond_to(:speaks_french=)
|
198
|
+
sample.should respond_to(:speaks_german=)
|
199
|
+
sample.should respond_to(:speaks_japanese=)
|
200
|
+
|
201
|
+
TestOptionPrefix2.should respond_to(:speaks_english)
|
202
|
+
TestOptionPrefix2.should respond_to(:speaks_french)
|
203
|
+
TestOptionPrefix2.should respond_to(:speaks_german)
|
204
|
+
TestOptionPrefix2.should respond_to(:speaks_japanese)
|
205
|
+
|
206
|
+
sample.should_not respond_to(:japanese?)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# _ _ _
|
211
|
+
# (_)__| (_)_ __
|
212
|
+
# _(_-< | | ' \
|
213
|
+
# (_)__/_|_|_|_|_|
|
214
|
+
#
|
215
|
+
|
216
|
+
describe ":slim" do
|
217
|
+
it 'should not generate instance nor class members when true is passed' do
|
218
|
+
named_model('TestOptionSlim1') do
|
219
|
+
as_set :spoken_languages, [:english, :french, :german, :japanese], slim: true
|
220
|
+
end
|
221
|
+
|
222
|
+
TestOptionSlim1.should_not respond_to(:english)
|
223
|
+
TestOptionSlim1.should_not respond_to(:french)
|
224
|
+
TestOptionSlim1.should_not respond_to(:german)
|
225
|
+
TestOptionSlim1.should_not respond_to(:japanese)
|
226
|
+
|
227
|
+
sample = TestOptionSlim1.new
|
228
|
+
sample.should_not respond_to(:english?)
|
229
|
+
sample.should_not respond_to(:french?)
|
230
|
+
sample.should_not respond_to(:german?)
|
231
|
+
sample.should_not respond_to(:japanese?)
|
232
|
+
|
233
|
+
sample.should_not respond_to(:english=)
|
234
|
+
sample.should_not respond_to(:french=)
|
235
|
+
sample.should_not respond_to(:german=)
|
236
|
+
sample.should_not respond_to(:japanese=)
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'should only generate instance members when :class is passed' do
|
240
|
+
named_model('TestOptionSlim2') do
|
241
|
+
as_set :spoken_languages, [:english, :french, :german, :japanese], slim: :class
|
242
|
+
end
|
243
|
+
|
244
|
+
TestOptionSlim2.should_not respond_to(:english)
|
245
|
+
TestOptionSlim2.should_not respond_to(:french)
|
246
|
+
TestOptionSlim2.should_not respond_to(:german)
|
247
|
+
TestOptionSlim2.should_not respond_to(:japanese)
|
248
|
+
|
249
|
+
sample = TestOptionSlim2.new
|
250
|
+
sample.should respond_to(:english?)
|
251
|
+
sample.should respond_to(:french?)
|
252
|
+
sample.should respond_to(:german?)
|
253
|
+
sample.should respond_to(:japanese?)
|
254
|
+
|
255
|
+
sample.should respond_to(:english=)
|
256
|
+
sample.should respond_to(:french=)
|
257
|
+
sample.should respond_to(:german=)
|
258
|
+
sample.should respond_to(:japanese=)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# _ _ _
|
263
|
+
# (_)_ __ _| |_ (_)_ _ _ _
|
264
|
+
# _\ V V / ' \| | ' \ || |
|
265
|
+
# (_)\_/\_/|_||_|_|_||_\_, |
|
266
|
+
# |__/
|
267
|
+
|
268
|
+
describe ':whiny' do
|
269
|
+
it 'should not raise exception on invalid value' do
|
270
|
+
named_model('TestOptionWhiny1') do
|
271
|
+
as_set :spoken_languages, [:english, :french, :german, :japanese], whiny: false
|
272
|
+
end
|
273
|
+
|
274
|
+
sample = TestOptionWhiny1.new
|
275
|
+
expect { sample.spoken_languages = [:french, :italian, :japanese] }.to_not raise_error
|
276
|
+
sample.spoken_languages.should == [:french, :japanese]
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
def named_model(class_name, &block)
|
4
|
+
begin
|
5
|
+
return class_name.constantize
|
6
|
+
rescue NameError
|
7
|
+
klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
|
8
|
+
klass.module_eval do
|
9
|
+
self.table_name = 'dummies'
|
10
|
+
instance_eval &block
|
11
|
+
end
|
12
|
+
klass
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
17
|
+
|
18
|
+
ActiveRecord::Base.connection.create_table :dummies do |t|
|
19
|
+
t.integer :values_cd
|
20
|
+
t.integer :values_with_default_cd, default: 2
|
21
|
+
t.integer :spoken_languages_cd
|
22
|
+
t.integer :custom_name
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple_set
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Romain Tartière
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: simple_enum
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.6.8
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.6.8
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- romain@blogreen.org
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- .rspec
|
78
|
+
- .travis.yml
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- lib/simple_set.rb
|
84
|
+
- lib/simple_set/set_hash.rb
|
85
|
+
- lib/simple_set/version.rb
|
86
|
+
- simple_set.gemspec
|
87
|
+
- spec/simple_set_spec.rb
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
- spec/support/models.rb
|
90
|
+
homepage: https://github.com/smortex/simple_set
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
metadata: {}
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 2.2.1
|
111
|
+
signing_key:
|
112
|
+
specification_version: 4
|
113
|
+
summary: Simple set-like field support for ActiveModel
|
114
|
+
test_files:
|
115
|
+
- spec/simple_set_spec.rb
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
- spec/support/models.rb
|
118
|
+
has_rdoc:
|