defaultable 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/defaultable.gemspec CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Defaultable::VERSION
17
17
 
18
- gem.add_dependency("activesupport", "3.0")
18
+ gem.add_dependency("activesupport", ">= 3.0")
19
19
 
20
20
  gem.add_development_dependency("rspec", "~> 2.7")
21
21
  gem.add_development_dependency("pry")
@@ -0,0 +1,25 @@
1
+ module Defaultable
2
+ class Serialization
3
+ class_attribute :settings_class
4
+
5
+ # Called to deserialize data to ruby object.
6
+ def load(data)
7
+ if data
8
+ obj = YAML.load(data)
9
+
10
+ raise TypeError, "Deserialized object is not of type #{self.class.settings_class.name}. Got #{obj.class}" unless obj.is_a?(self.class.settings_class)
11
+
12
+ # The reason we do the following is because defaults may have changed
13
+ # after the point of serialization. To avoid not having them, we instantiate the class
14
+ # again, we the previous values. This prevents not having data.
15
+ obj.class.new(obj.as_hash)
16
+ end
17
+ end
18
+
19
+ # Called to convert from ruby object to serialized data.
20
+ def dump(obj)
21
+ raise TypeError, "Serialization failed: Object is not of type #{self.class.settings_class.name}." unless obj.is_a?(self.class.settings_class)
22
+ obj.to_yaml if obj
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,98 @@
1
+ module Defaultable
2
+ class Settings
3
+ class_attribute :defaults
4
+ attr_accessor :root_key, :parent
5
+
6
+ def initialize(hash=nil, root_key=nil, parent=nil, skip_defaults=false)
7
+ @table = {}
8
+
9
+ self.root_key = root_key if root_key
10
+ self.parent = parent if parent
11
+
12
+ if !skip_defaults && !self.class.defaults.nil?
13
+ recursive_hash_assignment self.class.defaults
14
+ end
15
+
16
+ if !hash.nil? && hash.kind_of?(Hash)
17
+ recursive_hash_assignment hash
18
+ end
19
+ end
20
+
21
+ def method_missing(message, *args, &block)
22
+ # puts "Message: #{message}", "Args: #{args}", "\n"
23
+
24
+ if !(message.to_s =~ /^(.*)=$/) && @table.has_key?(message.to_s)
25
+ @table[message.to_s]
26
+ elsif message.to_s =~ /^(.*)\?$/
27
+ @table.has_key?(message.to_s.gsub(/\?$/, ''))
28
+ elsif message.to_s =~ /^(.*)=$/
29
+ key = message.to_s.gsub(/=$/, '')
30
+ value = args.first
31
+
32
+ if value.kind_of?(Defaultable::Settings)
33
+ value.parent = self
34
+ value.root_key = key
35
+ end
36
+
37
+ @table[key] = value
38
+ end
39
+ end
40
+
41
+ def as_hash
42
+ @table.inject({}) do |hash, (key, val)|
43
+ if val.kind_of?(Defaultable::Settings)
44
+ val = val.as_hash
45
+ else
46
+ val
47
+ end
48
+
49
+ hash[key] = val
50
+ hash
51
+ end
52
+ end
53
+
54
+ def has_parent?
55
+ !!self.parent
56
+ end
57
+
58
+ def recursive_hash_assignment(hash)
59
+ hash.each do |key, value|
60
+ if value.kind_of?(Hash)
61
+ key_aware_assignment(key, value)
62
+ else
63
+ self.send("#{key}=", value)
64
+ end
65
+ end
66
+ end
67
+
68
+ def key_aware_assignment(key, hash)
69
+ if self.send("#{key}?")
70
+ instance = self.send(key)
71
+
72
+ if instance.kind_of?(Defaultable::Settings)
73
+ instance.recursive_hash_assignment(hash)
74
+ self.send("#{key}=", instance)
75
+ else
76
+ self.send("#{key}=", hash)
77
+ end
78
+ else
79
+ self.send("#{key}=", self.class.new(hash, key, self, true))
80
+ end
81
+ end
82
+
83
+ class << self
84
+ def set_defaults(settings, env=nil)
85
+ case settings
86
+ when Hash
87
+ self.defaults = settings
88
+ when String
89
+ yaml = YAML.load_file(settings)
90
+ yaml = yaml[env] if env
91
+ self.defaults = yaml
92
+ else
93
+ raise ArgumentError, "You must supply a hash or a file name for default settings"
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -1,3 +1,3 @@
1
1
  module Defaultable
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/defaultable.rb CHANGED
@@ -3,85 +3,6 @@ require 'yaml'
3
3
  require 'active_support/core_ext/class/attribute'
4
4
 
5
5
  module Defaultable
6
- class Settings
7
- class_attribute :defaults
8
- attr_accessor :root_key, :parent
9
-
10
- def initialize(hash=nil, root_key=nil, parent=nil)
11
- @table = {}
12
-
13
- if root_key
14
- self.root_key = root_key
15
- end
16
-
17
- if parent
18
- self.parent = parent
19
- end
20
-
21
- if !hash.nil? && hash.kind_of?(Hash)
22
- hash.each do |key, value|
23
- if value.kind_of?(Hash)
24
- send("#{key}=", Defaultable::Settings.new(value, key, self))
25
- else
26
- self.send("#{key}=", value)
27
- end
28
- end
29
- end
30
- end
31
-
32
- def method_missing(message, *args, &block)
33
- # puts "Message: #{message}", "Args: #{args}", "\n"
34
-
35
- if !(message.to_s =~ /^(.*)=$/) && @table.has_key?(message.to_s)
36
- @table[message.to_s]
37
- elsif message.to_s =~ /^(.*)=$/
38
- @table[message.to_s.gsub(/=$/, '')] = args.first
39
- elsif !(message.to_s =~ /^(.*)=$/)
40
- # We're looking for a default
41
- default_settings = self.class.defaults
42
-
43
- # If we have a parent, we need to traverse to the top of all of the method calls (root_keys), then go back down them
44
- if self.parent
45
- root_keys = []
46
- current_parent = self
47
- while current_parent.has_parent? do
48
- root_keys << current_parent.root_key
49
- current_parent = current_parent.parent
50
- end
51
-
52
- root_keys.reverse.each do |key|
53
- default_settings = default_settings.send(key)
54
- end
55
-
56
- return default_settings.send(message)
57
- # If don't have a parent, just send the message to the defaults outright
58
- else
59
- default_settings.send(message)
60
- end
61
- end
62
- end
63
-
64
- def as_hash
65
- @table
66
- end
67
-
68
- def has_parent?
69
- !!self.parent
70
- end
71
-
72
- class << self
73
- def set_defaults(settings, env=nil)
74
- case settings
75
- when Hash
76
- self.defaults = self.new(settings)
77
- when String
78
- yaml = YAML.load_file(settings)
79
- yaml = yaml[env] if env
80
- self.defaults = self.new(yaml)
81
- else
82
- raise ArgumentError, "You must supply a hash or a file name for default settings"
83
- end
84
- end
85
- end
86
- end
6
+ autoload :Serialization, 'defaultable/serialization'
7
+ autoload :Settings, 'defaultable/settings'
87
8
  end
@@ -33,93 +33,110 @@ describe Defaultable::Settings do
33
33
  setting.parent.child.should eq('Rob')
34
34
  end
35
35
 
36
- it "should have default settings" do
37
- Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
38
- Defaultable::Settings.defaults.should be_kind_of(Defaultable::Settings)
36
+ it "should have a question mark method for keys" do
37
+ setting = Defaultable::Settings.new(:foo => 'bar')
38
+ setting.foo?.should be_true
39
39
  end
40
40
 
41
- it "should have a default setting for a key" do
42
- Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
41
+ describe "Defaults" do
42
+ it "should have default settings" do
43
+ Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
44
+ Defaultable::Settings.defaults.should be_kind_of(Hash)
45
+ end
43
46
 
44
- setting = Defaultable::Settings.new
45
- setting.grandparent.should be_kind_of Defaultable::Settings
46
- end
47
+ it "should have a default setting for a key" do
48
+ Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
47
49
 
48
- it "should have another key for another setting" do
49
- Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
50
+ setting = Defaultable::Settings.new
51
+ setting.grandparent.should be_kind_of Defaultable::Settings
52
+ end
50
53
 
51
- setting = Defaultable::Settings.new
52
- setting.grandparent.child.grandchild1.should eq('robert')
53
- end
54
+ it "should have another key for another setting" do
55
+ Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
56
+
57
+ setting = Defaultable::Settings.new
58
+ setting.grandparent.child.grandchild1.should eq('robert')
59
+ end
54
60
 
55
- it "should set a key but still have defaults" do
56
- Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
61
+ it "should set a key but still have defaults" do
62
+ Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
57
63
 
58
- setting = Defaultable::Settings.new({
59
- :grandparent => {
60
- :child => {
61
- :grandchild3 => 'hurdur'
64
+ setting = Defaultable::Settings.new({
65
+ :grandparent => {
66
+ :child => {
67
+ :grandchild3 => 'hurdur'
68
+ }
62
69
  }
63
- }
64
- })
70
+ })
65
71
 
66
- setting.grandparent.child.grandchild3.should eq('hurdur')
67
- setting.grandparent.child.grandchild2.should eq('brian')
68
- end
72
+ setting.grandparent.child.grandchild3.should eq('hurdur')
73
+ setting.grandparent.child.grandchild2.should eq('brian')
74
+ end
69
75
 
70
- it "should be able to overwrite a default" do
71
- Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
76
+ it "should be able to overwrite a default" do
77
+ Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
72
78
 
73
- setting = Defaultable::Settings.new({
74
- :grandparent => {
75
- :child => {
76
- :grandchild3 => 'hurdur'
79
+ setting = Defaultable::Settings.new({
80
+ :grandparent => {
81
+ :child => {
82
+ :grandchild3 => 'hurdur'
83
+ }
77
84
  }
78
- }
79
- })
85
+ })
80
86
 
81
- setting.grandparent.child.grandchild3.should eq('hurdur')
82
- setting.grandparent.child.grandchild2 = 'drpepper'
83
- setting.grandparent.child.grandchild2.should eq('drpepper')
84
- end
87
+ setting.grandparent.child.grandchild3.should eq('hurdur')
88
+ setting.grandparent.child.grandchild2 = 'drpepper'
89
+ setting.grandparent.child.grandchild2.should eq('drpepper')
90
+ end
85
91
 
86
- it "should be able to set a key in the middle of defaults" do
87
- Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
92
+ it "should be able to set a key in the middle of defaults" do
93
+ Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/test.yml'
88
94
 
89
- setting = Defaultable::Settings.new({
90
- :grandparent => {
91
- :child => {
92
- :grandchild3 => 'hurdur'
95
+ setting = Defaultable::Settings.new({
96
+ :grandparent => {
97
+ :child => {
98
+ :grandchild3 => 'hurdur'
99
+ }
93
100
  }
94
- }
95
- })
101
+ })
96
102
 
97
- setting.grandparent.child.grandchild3.should eq('hurdur')
98
- setting.grandparent.someotherkey = 'saweet'
99
- setting.grandparent.someotherkey.should eq('saweet')
100
- end
103
+ setting.grandparent.child.grandchild3.should eq('hurdur')
104
+ setting.grandparent.someotherkey = 'saweet'
105
+ setting.grandparent.someotherkey.should eq('saweet')
106
+ end
101
107
 
102
- it "should be able to set a hash for defaults" do
103
- Defaultable::Settings.set_defaults :child => 'sxephil'
108
+ it "should be able to set a hash for defaults" do
109
+ Defaultable::Settings.set_defaults :child => 'sxephil'
104
110
 
105
- setting = Defaultable::Settings.new
106
- setting.child.should eq('sxephil')
107
- end
111
+ setting = Defaultable::Settings.new
112
+ setting.child.should eq('sxephil')
113
+ end
108
114
 
109
- it "should accept a filename with an environment" do
110
- Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/env_test.yml', 'development'
115
+ it "should accept a filename with an environment" do
116
+ Defaultable::Settings.set_defaults File.expand_path('../', __FILE__) + '/env_test.yml', 'development'
111
117
 
112
- setting = Defaultable::Settings.new
113
- setting.setting_key.should eq('somevalue')
118
+ setting = Defaultable::Settings.new
119
+ setting.setting_key.should eq('somevalue')
120
+ end
114
121
  end
115
122
 
116
- it "should be extendable" do
117
- class DummySetting < Defaultable::Settings
118
- set_defaults :movie => 'Iron Man'
123
+ describe "Extendable" do
124
+ it "should be extendable" do
125
+ class DummySetting < Defaultable::Settings
126
+ set_defaults :movie => 'Iron Man'
127
+ end
128
+
129
+ setting = DummySetting.new
130
+ setting.movie.should eq('Iron Man')
119
131
  end
120
132
 
121
- setting = DummySetting.new
122
- setting.movie.should eq('Iron Man')
133
+ it "should return settings the same class of the extension for detauls" do
134
+ class DummySetting < Defaultable::Settings
135
+ set_defaults :movie => 'Iron Man'
136
+ end
137
+
138
+ DummySetting.defaults.should be_a Hash
139
+ end
123
140
  end
124
141
 
125
142
  describe "Hashes" do
@@ -139,4 +156,26 @@ describe Defaultable::Settings do
139
156
  setting.as_hash['name'].should eq('Robert')
140
157
  end
141
158
  end
159
+
160
+ describe "Defaults" do
161
+ before(:each) do
162
+ class DummySetting < Defaultable::Settings
163
+ set_defaults :movie => {:name => 'Iron Man' }
164
+ end
165
+ end
166
+
167
+ it "should have a key from defaults on initialization" do
168
+ setting = DummySetting.new
169
+ setting.movie?.should be_true
170
+ end
171
+
172
+ it "should have a hash with a length from defaults on initialization" do
173
+ setting = DummySetting.new
174
+ setting.as_hash.length.should eq(1)
175
+ end
176
+
177
+ it "should mash defaults together with new settings" do
178
+ setting = DummySetting.new(:movie => { :genre => 'asdf' })
179
+ end
180
+ end
142
181
  end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Defaultable::Serialization do
4
+ before(:each) do
5
+ class DummySetting < Defaultable::Settings; end
6
+ Defaultable::Serialization.settings_class = DummySetting
7
+ end
8
+
9
+ it "should set a class for settings" do
10
+ Defaultable::Serialization.settings_class.should eq(DummySetting)
11
+ end
12
+
13
+ it "should serialize a settings object" do
14
+ encoder = Defaultable::Serialization.new
15
+ settings = DummySetting.new
16
+
17
+ settings.foo = 'bar'
18
+ serialized = encoder.dump(settings)
19
+ serialized.should be_a String
20
+ end
21
+
22
+ it "should deserialize a settings object back to a kind of Defaultable::Settings" do
23
+ encoder = Defaultable::Serialization.new
24
+ settings = DummySetting.new
25
+
26
+ settings.foo = 'bar'
27
+ serialized = encoder.dump(settings)
28
+
29
+ encoder.load(serialized).should be_kind_of Defaultable::Settings
30
+ end
31
+
32
+ it "should throw an exception when the class doesn't match the settings class on load" do
33
+ encoder = Defaultable::Serialization.new
34
+
35
+ lambda { encoder.load('adfghjsfjdhg') }.should raise_error TypeError
36
+ end
37
+
38
+ it "should throw an exception when the class doesn't match the settings class on dump" do
39
+ encoder = Defaultable::Serialization.new
40
+
41
+ lambda { encoder.dump('adfghjsfjdhg'.to_yaml) }.should raise_error TypeError
42
+ end
43
+
44
+ it "should load with keys still in tact" do
45
+ encoder = Defaultable::Serialization.new
46
+ settings = DummySetting.new
47
+
48
+ settings.foo = 'bar'
49
+ serialized = encoder.dump(settings)
50
+ unserialized = encoder.load(serialized)
51
+
52
+ unserialized.foo.should eq('bar')
53
+ end
54
+
55
+ it "should load defaults in after the fact" do
56
+ encoder = Defaultable::Serialization.new
57
+ settings = DummySetting.new
58
+
59
+ settings.foo = 'bar'
60
+ serialized = encoder.dump(settings)
61
+
62
+ DummySetting.set_defaults :bobby => 'tables'
63
+
64
+ unserialized = encoder.load(serialized)
65
+ unserialized.bobby?.should be_true
66
+ end
67
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: defaultable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-15 00:00:00.000000000 Z
12
+ date: 2011-12-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &70138640817240 !ruby/object:Gem::Requirement
16
+ requirement: &70278791694720 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - =
19
+ - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
21
  version: '3.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70138640817240
24
+ version_requirements: *70278791694720
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &70138640816040 !ruby/object:Gem::Requirement
27
+ requirement: &70278791693100 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '2.7'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70138640816040
35
+ version_requirements: *70278791693100
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: pry
38
- requirement: &70138640815100 !ruby/object:Gem::Requirement
38
+ requirement: &70278791692600 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70138640815100
46
+ version_requirements: *70278791692600
47
47
  description: Defaultable is an extendable class to allow easy method chaining for
48
48
  settings along with defaults.
49
49
  email:
@@ -59,9 +59,12 @@ files:
59
59
  - Rakefile
60
60
  - defaultable.gemspec
61
61
  - lib/defaultable.rb
62
+ - lib/defaultable/serialization.rb
63
+ - lib/defaultable/settings.rb
62
64
  - lib/defaultable/version.rb
63
65
  - spec/defaultable_spec.rb
64
66
  - spec/env_test.yml
67
+ - spec/serialization_spec.rb
65
68
  - spec/spec_helper.rb
66
69
  - spec/test.yml
67
70
  homepage: https://github.com/bobbytables/defaultable
@@ -91,5 +94,6 @@ summary: Settings made easy.
91
94
  test_files:
92
95
  - spec/defaultable_spec.rb
93
96
  - spec/env_test.yml
97
+ - spec/serialization_spec.rb
94
98
  - spec/spec_helper.rb
95
99
  - spec/test.yml