defaultable 0.0.3 → 0.0.4

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/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