serial_preference 0.2.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.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
|