serial_preference 0.2.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/README.md +22 -13
- data/Rakefile +6 -0
- data/lib/serial_preference/has_preference_map.rb +49 -60
- data/lib/serial_preference/preference_definition.rb +83 -0
- data/lib/serial_preference/preferenzer.rb +81 -0
- data/lib/serial_preference/version.rb +1 -1
- data/lib/serial_preference.rb +4 -98
- data/serial_preference.gemspec +5 -0
- data/spec/database.yml +3 -0
- data/spec/fixtures/dummy_class.rb +12 -0
- data/spec/has_preference_map_spec.rb +83 -0
- data/spec/preference_definition_spec.rb +184 -0
- data/spec/preferenzer_spec.rb +111 -0
- data/spec/spec_helper.rb +24 -0
- metadata +88 -5
- data/lib/serial_preference/preference.rb +0 -55
- data/lib/serial_preference/preference_group.rb +0 -51
data/.gitignore
CHANGED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-c
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -36,38 +36,47 @@ Or install it yourself as:
|
|
36
36
|
````ruby
|
37
37
|
class Company < ActiveRecord::Base
|
38
38
|
|
39
|
-
include
|
39
|
+
include SerialPreference::HasSerialPreferences
|
40
40
|
|
41
|
-
|
41
|
+
preferences do
|
42
42
|
|
43
|
-
preference :taxable data_type: :boolean, required: true
|
44
|
-
preference :vat_no required: false
|
43
|
+
preference :taxable data_type: :boolean, required: true
|
44
|
+
preference :vat_no required: false
|
45
45
|
preference :max_invoice_items data_type: :integer
|
46
46
|
|
47
|
+
float :rate_of_interest
|
48
|
+
|
47
49
|
# default data type is :string
|
48
|
-
# default label is name of preference titleized
|
49
50
|
# if the preference is required, then a validation is added to the model
|
50
51
|
# if the data type is numerical, then a numericality validation is added
|
51
52
|
# preferences can be grouped in preference groups
|
52
53
|
|
53
|
-
preference_group
|
54
|
+
preference_group "Preferred Ledgers" do
|
54
55
|
income_ledger_id data_type: :integer, default: 1
|
55
56
|
end
|
56
57
|
|
57
|
-
|
58
|
+
password field_type: :password
|
58
59
|
|
59
|
-
|
60
|
-
+ :name_of_another_preference, default: "Hello"
|
60
|
+
end
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
end
|
62
|
+
end
|
63
|
+
````
|
65
64
|
|
66
|
-
|
65
|
+
* Fetching Preference/Groups
|
67
66
|
|
67
|
+
````ruby
|
68
|
+
# something you can customize in your form perhaps?
|
69
|
+
Company.preference_groups.each do |pg| # => returns an array of preference groups
|
70
|
+
# pg.name => Name of Preference Group as specified in map e.g. Preferred Ledgers
|
71
|
+
# pg.preferences => Hash of Preference Definitions keyed by Preference Name e.g. :taxable, :vat_no etc.
|
72
|
+
pg.preferences.values.each do |preference|
|
73
|
+
# preference => PreferenceDefinition
|
74
|
+
f.input preference.name, required: preference.required?, placeholder: preference.default, as: preference.field_type
|
75
|
+
end
|
68
76
|
end
|
69
77
|
````
|
70
78
|
|
79
|
+
|
71
80
|
## Contributing
|
72
81
|
|
73
82
|
1. Fork it
|
data/Rakefile
CHANGED
@@ -1,78 +1,67 @@
|
|
1
|
-
module
|
2
|
-
|
1
|
+
module SerialPreference
|
2
|
+
module HasSerialPreferences
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :_preferences_attribute
|
7
|
+
self._preferences_attribute = :preferences
|
8
|
+
class_attribute :_preference_map
|
9
|
+
self._preference_map = SerialPreference::Preferenzer.new
|
10
|
+
end
|
3
11
|
|
4
|
-
|
5
|
-
class_attribute :preference_context
|
6
|
-
class_attribute :preference_storage_attribute
|
7
|
-
self.preference_storage_attribute = :preferences
|
8
|
-
self.preference_context = "#{preference_storage_attribute}_#{table_name.downcase}".to_sym
|
9
|
-
end
|
12
|
+
module ClassMethods
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
+
def preference_groups
|
15
|
+
_preference_map.preference_groups
|
16
|
+
end
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
def preferences(storage_attribute = nil, &block)
|
19
|
+
self._preferences_attribute = storage_attribute || self._preferences_attribute
|
20
|
+
_preference_map.draw(&block)
|
21
|
+
build_preference_definitions
|
22
|
+
end
|
18
23
|
|
19
|
-
|
20
|
-
SerialPreference::Preferenzer.preferences_for(self.class.preference_context)
|
21
|
-
end
|
24
|
+
private
|
22
25
|
|
23
|
-
|
26
|
+
def build_preference_definitions
|
27
|
+
serialize self._preferences_attribute, Hash
|
24
28
|
|
25
|
-
|
26
|
-
SerialPreference::Preferenzer.group_for(preference_context).try(:values) || []
|
27
|
-
end
|
29
|
+
_preference_map.all_preference_definitions.each do |preference|
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
key = preference.name
|
32
|
+
define_method("#{key}=") do |value|
|
33
|
+
write_preference_attribute(_preferences_attribute,key,preference.value(value))
|
34
|
+
end
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
preferences = SerialPreference::Preferenzer.draw(preference_context,&block)
|
36
|
+
define_method(key) do
|
37
|
+
value = read_preference_attribute(_preferences_attribute,key)
|
38
|
+
preference.value(value)
|
39
|
+
end
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
+
if preference.boolean?
|
42
|
+
define_method("#{key}?") do
|
43
|
+
read_preference_attribute(_preferences_attribute,key).present?
|
44
|
+
end
|
45
|
+
end
|
41
46
|
|
42
|
-
def default_preference_for(name)
|
43
|
-
SerialPreference::Preferenzer.preference(name,nil,preference_context)
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def make_functions(preferences,store_attribute,context)
|
49
|
-
serialize store_attribute, Hash
|
50
|
-
|
51
|
-
preferences.each do |preference|
|
52
|
-
key = preference.name
|
53
|
-
define_method("#{key}=") do |value|
|
54
|
-
send(store_attribute)[key] = SerialPreference::Preferenzer.preference(key,value,context)
|
55
|
-
send("#{store_attribute}_will_change!")
|
56
47
|
end
|
48
|
+
end
|
49
|
+
end
|
57
50
|
|
58
|
-
|
59
|
-
value = send(store_attribute)[key]
|
60
|
-
SerialPreference::Preferenzer.preference(key,value,context)
|
61
|
-
end
|
51
|
+
protected
|
62
52
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
if preference.numerical?
|
68
|
-
opts[:numericality] = true
|
69
|
-
opts[:allow_blank] = true unless opts[:presence].present?
|
70
|
-
end
|
71
|
-
validates key, opts if opts.present?
|
53
|
+
def read_preference_attribute(store_attribute, key)
|
54
|
+
attribute = send(store_attribute)
|
55
|
+
attribute[key]
|
56
|
+
end
|
72
57
|
|
58
|
+
def write_preference_attribute(store_attribute, key, value)
|
59
|
+
attribute = send(store_attribute)
|
60
|
+
if value != attribute[key]
|
61
|
+
send :"#{store_attribute}_will_change!"
|
62
|
+
attribute[key] = value
|
73
63
|
end
|
74
64
|
end
|
75
65
|
|
76
66
|
end
|
77
|
-
|
78
|
-
end
|
67
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module SerialPreference
|
2
|
+
class PreferenceDefinition
|
3
|
+
|
4
|
+
SUPPORTED_TYPES = [:string,:integer,:decimal,:float,:boolean]
|
5
|
+
|
6
|
+
attr_accessor :data_type, :name, :default, :required, :field_type
|
7
|
+
|
8
|
+
def initialize(name,*args)
|
9
|
+
opts = args.extract_options!
|
10
|
+
self.name = name.to_s
|
11
|
+
opts.assert_valid_keys(:data_type,:default,:required,:field_type)
|
12
|
+
self.data_type = @type = opts[:data_type] || :string
|
13
|
+
@column = ActiveRecord::ConnectionAdapters::Column.new(name.to_s,opts[:default],@type.to_s)
|
14
|
+
self.default = opts[:default]
|
15
|
+
self.required = !!opts[:required]
|
16
|
+
self.field_type = opts[:field_type]
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
@column.name
|
21
|
+
end
|
22
|
+
|
23
|
+
def default_value
|
24
|
+
@column.default
|
25
|
+
end
|
26
|
+
|
27
|
+
def required?
|
28
|
+
required
|
29
|
+
end
|
30
|
+
|
31
|
+
def numerical?
|
32
|
+
@column.number?
|
33
|
+
end
|
34
|
+
|
35
|
+
def boolean?
|
36
|
+
@column.type == :boolean
|
37
|
+
end
|
38
|
+
|
39
|
+
def type_cast(value)
|
40
|
+
v = @column.type_cast(value)
|
41
|
+
v.nil? ? default_value : v
|
42
|
+
end
|
43
|
+
|
44
|
+
def field_type
|
45
|
+
@field_type || (numerical? ? :string : data_type)
|
46
|
+
end
|
47
|
+
|
48
|
+
def query(value)
|
49
|
+
if !(value = type_cast(value))
|
50
|
+
false
|
51
|
+
elsif numerical?
|
52
|
+
!value.zero?
|
53
|
+
else
|
54
|
+
!value.blank?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def value(v)
|
59
|
+
v = v.nil? ? default : v
|
60
|
+
if !v.nil?
|
61
|
+
case data_type
|
62
|
+
when :string, :password
|
63
|
+
v.to_s
|
64
|
+
when :integer
|
65
|
+
v.respond_to?(:to_i) ? v.to_i : nil
|
66
|
+
when :float, :real
|
67
|
+
v.respond_to?(:to_f) ? v.to_f : nil
|
68
|
+
when :boolean
|
69
|
+
return false if v == 0
|
70
|
+
return false if v == ""
|
71
|
+
return false if v == nil
|
72
|
+
return false if v.to_s.downcase == "false"
|
73
|
+
return false if v == "0"
|
74
|
+
return false if v.to_s.downcase == "no"
|
75
|
+
!!v
|
76
|
+
else
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module SerialPreference
|
2
|
+
class Preferenzer
|
3
|
+
PreferenceGroup = Struct.new(:name,:preferences)
|
4
|
+
|
5
|
+
attr_reader :preference_groups, :current_group
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@preference_names_cache = HashWithIndifferentAccess.new
|
9
|
+
@preference_groups = []
|
10
|
+
activate_group
|
11
|
+
end
|
12
|
+
|
13
|
+
def draw(&block)
|
14
|
+
instance_exec(&block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def respond_to?(name)
|
18
|
+
[:string, :integer, :boolean, :float].include?(name) || @preference_names_cache[name].present? || super
|
19
|
+
end
|
20
|
+
|
21
|
+
def method_missing(name,*args,&block)
|
22
|
+
preference(name,args.extract_options!)
|
23
|
+
end
|
24
|
+
|
25
|
+
[:string,:integer,:boolean,:float].each do |dt|
|
26
|
+
define_method(dt) do |name,opts = {}|
|
27
|
+
preference(name,opts.merge!(:data_type => dt))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def preference(name,opts = {})
|
32
|
+
Array(name).each do |n|
|
33
|
+
push_preference SerialPreference::PreferenceDefinition.new(n.to_sym,opts)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
alias :pref :preference
|
37
|
+
|
38
|
+
def preference_group(name,&block)
|
39
|
+
activate_group(name)
|
40
|
+
instance_exec(&block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def all_preference_definitions
|
44
|
+
preference_groups.map{|x|x.preferences.values}.flatten
|
45
|
+
end
|
46
|
+
|
47
|
+
def all_preference_names
|
48
|
+
@preference_names_cache.keys
|
49
|
+
end
|
50
|
+
|
51
|
+
def all_groups
|
52
|
+
@preference_groups.map{|x|x.name}
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def activate_group(group_name = :base)
|
58
|
+
@current_group = find_or_create_group(group_name)
|
59
|
+
end
|
60
|
+
|
61
|
+
def push_preference(preference)
|
62
|
+
@preference_names_cache[preference.name] = 1
|
63
|
+
@current_group.preferences[preference.name] = preference
|
64
|
+
end
|
65
|
+
|
66
|
+
def find_or_create_group(name)
|
67
|
+
find_group(name) || create_group(name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def find_group(name)
|
71
|
+
@preference_groups.find{|x|x.name == name}
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_group(name = :base)
|
75
|
+
PreferenceGroup.new(name,{}).tap do |pg|
|
76
|
+
@preference_groups.push(pg)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
data/lib/serial_preference.rb
CHANGED
@@ -1,100 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'active_record'
|
2
3
|
require "serial_preference/version"
|
3
|
-
require 'serial_preference/
|
4
|
-
require
|
4
|
+
require 'serial_preference/preference_definition'
|
5
|
+
require "serial_preference/preferenzer"
|
5
6
|
require "serial_preference/has_preference_map"
|
6
|
-
|
7
|
-
module SerialPreference
|
8
|
-
class Preferenzer
|
9
|
-
|
10
|
-
include Singleton
|
11
|
-
|
12
|
-
attr_accessor :preference_groups, :current_context
|
13
|
-
|
14
|
-
def self.draw(context = :base, &block)
|
15
|
-
i = instance
|
16
|
-
i.preference_groups ||= {}
|
17
|
-
i.preference_groups[context] ||= {}
|
18
|
-
i.current_context = context
|
19
|
-
i.instance_exec(&block)
|
20
|
-
i.preferences_for(context)
|
21
|
-
end
|
22
|
-
|
23
|
-
def +(name,opts = {})
|
24
|
-
preference(name,opts)
|
25
|
-
end
|
26
|
-
|
27
|
-
def *(name,opts = {},&block)
|
28
|
-
preference_group(name,opts,&block)
|
29
|
-
end
|
30
|
-
|
31
|
-
def reset(context = :base)
|
32
|
-
self.preference_groups.try(:delete,context)
|
33
|
-
end
|
34
|
-
|
35
|
-
def preference(name,opts = {})
|
36
|
-
pg = base_group
|
37
|
-
pg.pref(name,opts)
|
38
|
-
end
|
39
|
-
|
40
|
-
def preference_group(name, opts={},&block)
|
41
|
-
self.preference_groups[current_context] ||= {}
|
42
|
-
self.preference_groups[current_context][name] ||= SerialPreference::PreferenceGroup.new(name,opts)
|
43
|
-
self.preference_groups[current_context][name].instance_exec(&block)
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.method_missing(name,*args,&block)
|
47
|
-
if instance.respond_to?(name)
|
48
|
-
instance.send(name,*args,&block)
|
49
|
-
else
|
50
|
-
super
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def all_preference_names(context = :base)
|
55
|
-
group_for(context).values.map do |pg|
|
56
|
-
pg.preferences.map do |pref|
|
57
|
-
pref.name
|
58
|
-
end
|
59
|
-
end.flatten
|
60
|
-
end
|
61
|
-
|
62
|
-
def preferences_for(context = :base)
|
63
|
-
group_for(context).values.map do |pg|
|
64
|
-
pg.preferences.map do |pref|
|
65
|
-
pref
|
66
|
-
end
|
67
|
-
end.flatten
|
68
|
-
end
|
69
|
-
|
70
|
-
def each_preference(context = :base)
|
71
|
-
group_for(context).values.each do |pg|
|
72
|
-
pg.preferences.each do |pref|
|
73
|
-
yield(pref)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def preference(name,value,context = :base)
|
79
|
-
p = preferences_for(context).find{|x| x.name == name }
|
80
|
-
p ? p.value(value) : nil
|
81
|
-
end
|
82
|
-
|
83
|
-
def group_for(context = :base)
|
84
|
-
preference_groups[context] || {}
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
|
89
|
-
def base_group
|
90
|
-
@base_group ||= begin
|
91
|
-
pg = SerialPreference::PreferenceGroup.new(:base,:label => current_context.to_s.titleize)
|
92
|
-
self.preference_groups[current_context] ||= {}
|
93
|
-
self.preference_groups[current_context][:base] = pg
|
94
|
-
pg
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
data/serial_preference.gemspec
CHANGED
@@ -18,5 +18,10 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
20
|
gem.add_runtime_dependency "activesupport", ">= 3.0.0"
|
21
|
+
gem.add_runtime_dependency "activerecord", ">= 3.0.0"
|
22
|
+
|
23
|
+
gem.add_development_dependency 'sqlite3'
|
24
|
+
gem.add_development_dependency 'rspec-rails'
|
25
|
+
gem.add_development_dependency "shoulda"
|
21
26
|
|
22
27
|
end
|
data/spec/database.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class DummyClass < ActiveRecord::Base
|
2
|
+
include SerialPreference::HasSerialPreferences
|
3
|
+
preferences do
|
4
|
+
preference :taxable, data_type: :boolean, required: true
|
5
|
+
preference :required_number, data_type: :integer, required: :true
|
6
|
+
preference :vat_no, required: false
|
7
|
+
preference :max_invoice_items, data_type: :integer
|
8
|
+
preference_group "Preferred Ledgers" do
|
9
|
+
income_ledger_id data_type: :integer, default: 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fixtures/dummy_class'
|
3
|
+
describe SerialPreference::HasSerialPreferences do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
rebuild_model
|
7
|
+
end
|
8
|
+
|
9
|
+
context "default behaviour" do
|
10
|
+
it "should return preferences as a default _preferences_attribute" do
|
11
|
+
DummyClass._preferences_attribute.should eq(:preferences)
|
12
|
+
end
|
13
|
+
it "should return settings as a _preferences_attribute" do
|
14
|
+
class OverriddenPreferenceAttributeClass < ActiveRecord::Base
|
15
|
+
include SerialPreference::HasSerialPreferences
|
16
|
+
preferences :settings do
|
17
|
+
preference :abc
|
18
|
+
end
|
19
|
+
end
|
20
|
+
OverriddenPreferenceAttributeClass._preferences_attribute.should eq(:settings)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "class methods behaviour" do
|
25
|
+
it "should be possible to describe preference map thru preferences" do
|
26
|
+
DummyClass.respond_to?(:preferences).should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be possble to retrieve preference groups from class" do
|
30
|
+
DummyClass.respond_to?(:preference_groups).should be_true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
context "should define accessors" do
|
36
|
+
it "should have readers available" do
|
37
|
+
d = DummyClass.new
|
38
|
+
d.respond_to?(:taxable).should be_true
|
39
|
+
d.respond_to?(:vat_no).should be_true
|
40
|
+
d.respond_to?(:max_invoice_items).should be_true
|
41
|
+
d.respond_to?(:income_ledger_id).should be_true
|
42
|
+
d.respond_to?(:read_preference_attribute).should be_true
|
43
|
+
d.respond_to?(:write_preference_attribute).should be_true
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should have writers available" do
|
47
|
+
d = DummyClass.new
|
48
|
+
d.respond_to?(:taxable=).should be_true
|
49
|
+
d.respond_to?(:vat_no=).should be_true
|
50
|
+
d.respond_to?(:max_invoice_items=).should be_true
|
51
|
+
d.respond_to?(:income_ledger_id=).should be_true
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should have query methods available for booleans" do
|
55
|
+
DummyClass.new.respond_to?(:taxable?)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
=begin
|
61
|
+
context "should define validations" do
|
62
|
+
it "should define presence validation on required preferences" do
|
63
|
+
d = DummyClass.new
|
64
|
+
d.should validate_presence_of(:taxable)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should define presence and numericality on required preference which are numeric" do
|
68
|
+
d = DummyClass.new
|
69
|
+
d.taxable = true
|
70
|
+
d.should validate_presence_of(:required_number)
|
71
|
+
d.should validate_numericality_of(:required_number)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should define numericality on preference which are numeric" do
|
75
|
+
d = DummyClass.new
|
76
|
+
d.should validate_numericality_of(:required_number)
|
77
|
+
d.should validate_numericality_of(:income_ledger_id)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
=end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SerialPreference::PreferenceDefinition do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@blank_pref = described_class.new("whatever")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have proper accessors" do
|
10
|
+
[:data_type, :name, :default, :required, :field_type].each do |a|
|
11
|
+
@blank_pref.respond_to?(a).should be_true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should declare supported data types" do
|
16
|
+
described_class.constants.should include(:SUPPORTED_TYPES)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should stringify its name" do
|
20
|
+
described_class.new(:whatever).name.should eq("whatever")
|
21
|
+
end
|
22
|
+
|
23
|
+
context "required behaviour" do
|
24
|
+
it "should not be required when no required option provided" do
|
25
|
+
@blank_pref.should_not be_required
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be required when required option is truthy" do
|
29
|
+
[0,"yes","no","false",true].each do |truthy_values|
|
30
|
+
p = described_class.new("whatever",{required: truthy_values})
|
31
|
+
p.should be_required
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not be required when required option is falsy" do
|
36
|
+
[false,nil].each do |falsy_values|
|
37
|
+
p = described_class.new("whatever",{required: falsy_values})
|
38
|
+
p.should_not be_required
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "numericality behaviour" do
|
44
|
+
it "should not be numerical when no data_type is provided" do
|
45
|
+
@blank_pref.should_not be_numerical
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should be numerical when data_type is numerical" do
|
49
|
+
[:integer,:float,:decimal].each do |dt|
|
50
|
+
described_class.new("whatever",{data_type: dt}).should be_numerical
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should be not numerical when data_type is non numerical" do
|
55
|
+
[:string,:boolean,:password,:whatever].each do |dt|
|
56
|
+
described_class.new("whatever",{data_type: dt}).should_not be_numerical
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "default behaviour" do
|
62
|
+
it "should report correct name" do
|
63
|
+
@blank_pref.name.should eq("whatever")
|
64
|
+
end
|
65
|
+
it "should be a string" do
|
66
|
+
@blank_pref.data_type.should eq(:string)
|
67
|
+
end
|
68
|
+
it "should have nil default" do
|
69
|
+
@blank_pref.default.should be_nil
|
70
|
+
end
|
71
|
+
it "should be false for required" do
|
72
|
+
@blank_pref.required.should be_false
|
73
|
+
end
|
74
|
+
it "should have string field_type" do
|
75
|
+
@blank_pref.field_type.should eq(:string)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "field_type behaviour" do
|
80
|
+
it "should report field_type as provided" do
|
81
|
+
described_class.new("whatever",{field_type: :xyz}).field_type.should eq(:xyz)
|
82
|
+
end
|
83
|
+
it "should report string for numerical data types" do
|
84
|
+
described_class.new("whatever",{data_type: :integer}).field_type.should eq(:string)
|
85
|
+
end
|
86
|
+
it "should report data type for non numeric data types" do
|
87
|
+
p = described_class.new("whatever",{data_type: :xyz})
|
88
|
+
p.field_type.should eq(p.data_type)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "should report correct preferred values" do
|
93
|
+
|
94
|
+
context "when input is nil" do
|
95
|
+
it "should report nil when no default is given" do
|
96
|
+
@blank_pref.value(nil).should be_nil
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should report default when input is nil" do
|
100
|
+
p = described_class.new("whatever",{default: "dog"})
|
101
|
+
p.value(nil).should eq("dog")
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should report default in appropriate data type when input is nil" do
|
105
|
+
p = described_class.new("whatever",{default: "dog", data_type: :integer})
|
106
|
+
p.value(nil).should eq("dog".to_i)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "should report correct string/password values" do
|
111
|
+
before do
|
112
|
+
@preference = described_class.new("whatever",{data_type: :string})
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should return correct strings as passthru" do
|
116
|
+
["",3.0,[],{},"dog",1].each do |input_val|
|
117
|
+
@preference.value(input_val).should eq(input_val.to_s)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
context "should report correct integer values" do
|
124
|
+
before do
|
125
|
+
@preference = described_class.new("whatever",{data_type: :integer})
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should return correct integers" do
|
129
|
+
["",1,3.0,"dog"].each do |input_val|
|
130
|
+
@preference.value(input_val).should eq(input_val.to_i)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should report nil for non numeric input" do
|
135
|
+
[[],{}].each do |input_val|
|
136
|
+
@preference.value(input_val).should be_nil
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context "should report correct floaty/real values" do
|
142
|
+
before do
|
143
|
+
@preference = described_class.new("whatever",{data_type: :float})
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should return correct floats" do
|
147
|
+
["",1,3.0,"dog"].each do |input_val|
|
148
|
+
@preference.value(input_val).should eq(input_val.to_f)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should report nil for non numeric input" do
|
153
|
+
[[],{}].each do |input_val|
|
154
|
+
@preference.value(input_val).should be_nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "should report correct boolean values" do
|
160
|
+
before do
|
161
|
+
@preference = described_class.new("whatever",{data_type: :boolean})
|
162
|
+
end
|
163
|
+
it "should report false for falsy values" do
|
164
|
+
[nil,false].each do |falsy|
|
165
|
+
@preference.value(falsy).should be_false
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should report false for false looking values" do
|
170
|
+
[0,"0","false","FALSE","False","no","NO","No"].each do |falsy|
|
171
|
+
@preference.value(falsy).should be_false
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should report true for truthy values" do
|
176
|
+
["yes",true,100,0.1,[],{}].each do |truthy_value|
|
177
|
+
@preference.value(truthy_value).should be_true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SerialPreference::Preferenzer do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@base = described_class::PreferenceGroup.new(:base,{})
|
7
|
+
@preferenzer = described_class.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have proper readers" do
|
11
|
+
[:preference_groups,:preference,:preference_groups,:all_preference_definitions,:all_preference_names,:current_group].each do |a|
|
12
|
+
@preferenzer.should respond_to(a)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "default instance behaviour" do
|
17
|
+
it "should report empty preference groups" do
|
18
|
+
@preferenzer.preference_groups.should include(@base)
|
19
|
+
end
|
20
|
+
it "should report current_contex to be nil" do
|
21
|
+
@preferenzer.current_group.should eq(@base)
|
22
|
+
end
|
23
|
+
it "should report all preference name to be empty" do
|
24
|
+
@preferenzer.all_preference_names.should be_empty
|
25
|
+
end
|
26
|
+
it "should report all preference definitions to be empty" do
|
27
|
+
@preferenzer.all_preference_definitions.should be_empty
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "allows for preferences/groups to be setup using instance" do
|
32
|
+
|
33
|
+
it "should allow for addition of preference using pref" do
|
34
|
+
@preferenzer.pref("whatever")
|
35
|
+
@preferenzer.all_preference_names.should include("whatever")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should allow for addition of preference using preference" do
|
39
|
+
@preferenzer.preference("whatever")
|
40
|
+
@preferenzer.all_preference_names.should include("whatever")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should alias preference to pref" do
|
44
|
+
described_class.instance_method(:pref).should eq(described_class.instance_method(:preference))
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should allow for addition of preference group" do
|
48
|
+
@preferenzer.preference_group(:new_group) do
|
49
|
+
preference :new_preference
|
50
|
+
end
|
51
|
+
@preferenzer.all_preference_names.should include("new_preference")
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
context "allows for drawing of preference map" do
|
57
|
+
it "should setup preferences using draw" do
|
58
|
+
@preferenzer.draw do
|
59
|
+
preference :name
|
60
|
+
pref :age, data_type: :integer
|
61
|
+
pref :sex, default: "male"
|
62
|
+
preference_group "Email Notifications" do
|
63
|
+
email default: false
|
64
|
+
switch_off_hour default: 23
|
65
|
+
end
|
66
|
+
end
|
67
|
+
@preferenzer.all_preference_names.should include("age","name","sex","email","switch_off_hour")
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should allow for addition of preference in given context" do
|
71
|
+
@preferenzer.all_groups.should_not include(:new_group)
|
72
|
+
@preferenzer.preference_group(:new_group) do
|
73
|
+
preference "addition"
|
74
|
+
end
|
75
|
+
@preferenzer.all_preference_names.should include("addition")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should allow overriding of preference if defined twice" do
|
79
|
+
@preferenzer.preference_group(:overriding) do
|
80
|
+
preference :overriding_name
|
81
|
+
preference :overriding_name
|
82
|
+
end
|
83
|
+
@preferenzer.all_preference_names.should include("overriding_name", "overriding_name")
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should allow addition of preference to an existing preference group" do
|
87
|
+
@preferenzer.preference_group(:notifications) do
|
88
|
+
preference :new_preference
|
89
|
+
end
|
90
|
+
@preferenzer.all_preference_names.should include("new_preference")
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should allow for preference names to be strings or symbols" do
|
94
|
+
@preferenzer.preference_group(:notifications) do
|
95
|
+
preference "string"
|
96
|
+
preference :symbol
|
97
|
+
end
|
98
|
+
@preferenzer.all_preference_names.should include("string", "symbol")
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should allow for preference_group names to be strings or symbols" do
|
102
|
+
@preferenzer.preference_group(:symbol) do
|
103
|
+
preference "string"
|
104
|
+
end
|
105
|
+
@preferenzer.preference_group("string") do
|
106
|
+
preference :symbol
|
107
|
+
end
|
108
|
+
@preferenzer.all_groups.should include("string", :symbol)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift File.expand_path('..', __FILE__)
|
2
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
require 'active_support/all'
|
4
|
+
require 'active_record'
|
5
|
+
require 'rspec'
|
6
|
+
require 'shoulda'
|
7
|
+
require "serial_preference/version"
|
8
|
+
require 'serial_preference/preference_definition'
|
9
|
+
require "serial_preference/preferenzer"
|
10
|
+
require "serial_preference/has_preference_map"
|
11
|
+
|
12
|
+
FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
|
13
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
14
|
+
ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.dirname(__FILE__) + "/debug.log")
|
15
|
+
ActiveRecord::Base.establish_connection(config['test'])
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
end
|
19
|
+
|
20
|
+
def rebuild_model options = {}
|
21
|
+
ActiveRecord::Base.connection.create_table :dummy_classes, :force => true do |table|
|
22
|
+
table.column :preferences, :text
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serial_preference
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
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: 2012-09-
|
12
|
+
date: 2012-09-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -27,6 +27,70 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 3.0.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activerecord
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.0.0
|
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: 3.0.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: sqlite3
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec-rails
|
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: shoulda
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
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: '0'
|
30
94
|
description: Serialized Preferences for your models
|
31
95
|
email:
|
32
96
|
- aditya.sanghi@risingsuntech.net
|
@@ -35,16 +99,23 @@ extensions: []
|
|
35
99
|
extra_rdoc_files: []
|
36
100
|
files:
|
37
101
|
- .gitignore
|
102
|
+
- .rspec
|
38
103
|
- Gemfile
|
39
104
|
- LICENSE.txt
|
40
105
|
- README.md
|
41
106
|
- Rakefile
|
42
107
|
- lib/serial_preference.rb
|
43
108
|
- lib/serial_preference/has_preference_map.rb
|
44
|
-
- lib/serial_preference/
|
45
|
-
- lib/serial_preference/
|
109
|
+
- lib/serial_preference/preference_definition.rb
|
110
|
+
- lib/serial_preference/preferenzer.rb
|
46
111
|
- lib/serial_preference/version.rb
|
47
112
|
- serial_preference.gemspec
|
113
|
+
- spec/database.yml
|
114
|
+
- spec/fixtures/dummy_class.rb
|
115
|
+
- spec/has_preference_map_spec.rb
|
116
|
+
- spec/preference_definition_spec.rb
|
117
|
+
- spec/preferenzer_spec.rb
|
118
|
+
- spec/spec_helper.rb
|
48
119
|
homepage: ''
|
49
120
|
licenses: []
|
50
121
|
post_install_message:
|
@@ -57,16 +128,28 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
128
|
- - ! '>='
|
58
129
|
- !ruby/object:Gem::Version
|
59
130
|
version: '0'
|
131
|
+
segments:
|
132
|
+
- 0
|
133
|
+
hash: 617750894719650316
|
60
134
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
135
|
none: false
|
62
136
|
requirements:
|
63
137
|
- - ! '>='
|
64
138
|
- !ruby/object:Gem::Version
|
65
139
|
version: '0'
|
140
|
+
segments:
|
141
|
+
- 0
|
142
|
+
hash: 617750894719650316
|
66
143
|
requirements: []
|
67
144
|
rubyforge_project:
|
68
145
|
rubygems_version: 1.8.24
|
69
146
|
signing_key:
|
70
147
|
specification_version: 3
|
71
148
|
summary: Serialized Preferences for your models
|
72
|
-
test_files:
|
149
|
+
test_files:
|
150
|
+
- spec/database.yml
|
151
|
+
- spec/fixtures/dummy_class.rb
|
152
|
+
- spec/has_preference_map_spec.rb
|
153
|
+
- spec/preference_definition_spec.rb
|
154
|
+
- spec/preferenzer_spec.rb
|
155
|
+
- spec/spec_helper.rb
|
@@ -1,55 +0,0 @@
|
|
1
|
-
module SerialPreference
|
2
|
-
class Preference
|
3
|
-
|
4
|
-
SUPPORTED_TYPES = [:string,:integer,:real,:float,:boolean,:password]
|
5
|
-
|
6
|
-
attr_accessor :data_type, :name, :default, :required, :label, :hint, :field_type
|
7
|
-
|
8
|
-
def initialize(name,opts = {})
|
9
|
-
self.data_type = opts[:data_type] || :string
|
10
|
-
self.name = name
|
11
|
-
self.default = opts[:default]
|
12
|
-
self.required = !!opts[:required]
|
13
|
-
self.label = opts[:label]
|
14
|
-
self.hint = opts[:hint]
|
15
|
-
self.field_type = opts[:field_type]
|
16
|
-
end
|
17
|
-
|
18
|
-
def required?
|
19
|
-
required
|
20
|
-
end
|
21
|
-
|
22
|
-
def numerical?
|
23
|
-
[:integer,:float,:real].include?(data_type)
|
24
|
-
end
|
25
|
-
|
26
|
-
def field_type
|
27
|
-
@field_type || (numerical? ? :string : data_type)
|
28
|
-
end
|
29
|
-
|
30
|
-
def value(value)
|
31
|
-
value = value.nil? ? default : value
|
32
|
-
if !value.nil?
|
33
|
-
case data_type
|
34
|
-
when :string, :password
|
35
|
-
value.to_s
|
36
|
-
when :integer
|
37
|
-
value.to_i
|
38
|
-
when :float, :real
|
39
|
-
value.to_f
|
40
|
-
when :boolean
|
41
|
-
return false if value == 0
|
42
|
-
return false if value == ""
|
43
|
-
return false if value == nil
|
44
|
-
return false if value.to_s.downcase == "false"
|
45
|
-
return false if value == "0"
|
46
|
-
return false if value.to_s.downcase == "no"
|
47
|
-
!!value
|
48
|
-
else
|
49
|
-
nil
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
module SerialPreference
|
2
|
-
class PreferenceGroup
|
3
|
-
|
4
|
-
attr_accessor :name, :label
|
5
|
-
|
6
|
-
def initialize(name, opts = {})
|
7
|
-
@preferences = {}
|
8
|
-
@name = name
|
9
|
-
@label = opts[:label]
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_s
|
13
|
-
name.to_s
|
14
|
-
end
|
15
|
-
|
16
|
-
def titleize
|
17
|
-
label
|
18
|
-
end
|
19
|
-
|
20
|
-
def label
|
21
|
-
@label.presence || name.to_s.titleize
|
22
|
-
end
|
23
|
-
|
24
|
-
def preference_keys
|
25
|
-
@preferences.keys
|
26
|
-
end
|
27
|
-
|
28
|
-
def preferences
|
29
|
-
@preferences.values
|
30
|
-
end
|
31
|
-
|
32
|
-
def pref(name,opts = {})
|
33
|
-
@preferences[name] = Preference.new(name,opts)
|
34
|
-
end
|
35
|
-
|
36
|
-
SerialPreference::Preference::SUPPORTED_TYPES.each do |dt|
|
37
|
-
define_method dt do |name,opts = {}|
|
38
|
-
pref(name,opts.merge!(:data_type => dt))
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def respond_to?(name,*opts)
|
43
|
-
@preferences[name].present?
|
44
|
-
end
|
45
|
-
|
46
|
-
def method_missing(name,*opts,&block)
|
47
|
-
pref(name,*opts)
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|