chozo 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/chozo.gemspec CHANGED
@@ -7,6 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.description = %q{A collection of supporting libraries and Ruby core extensions}
8
8
  s.summary = s.description
9
9
  s.homepage = "https://github.com/reset/chozo"
10
+ s.license = "Apache 2.0"
10
11
 
11
12
  s.files = `git ls-files`.split($\)
12
13
  s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -1,4 +1,3 @@
1
- require 'forwardable'
2
1
  require 'chozo/varia_model'
3
2
 
4
3
  module Chozo
@@ -6,10 +5,15 @@ module Chozo
6
5
  # @author Jamie Winsor <jamie@vialstudios.com>
7
6
  # @api private
8
7
  class Abstract
8
+ extend Forwardable
9
9
  include VariaModel
10
10
 
11
11
  attr_accessor :path
12
12
 
13
+ def_delegator :to_hash, :slice
14
+ def_delegator :to_hash, :slice!
15
+ def_delegator :to_hash, :extract!
16
+
13
17
  # @param [String] path
14
18
  # @param [Hash] attributes
15
19
  def initialize(path = nil, attributes = {})
@@ -26,6 +30,10 @@ module Chozo
26
30
  self.attributes[key] = value
27
31
  end
28
32
 
33
+ def to_hash
34
+ self.attributes.to_hash.deep_symbolize_keys
35
+ end
36
+
29
37
  protected
30
38
 
31
39
  def mass_assign(new_attributes = {})
@@ -22,7 +22,7 @@ module Chozo
22
22
  path = File.expand_path(path)
23
23
  data = File.read(path)
24
24
  new(path).from_json(data)
25
- rescue Errno::ENOENT, Errno::EISDIR
25
+ rescue TypeError, Errno::ENOENT, Errno::EISDIR
26
26
  raise Chozo::Errors::ConfigNotFound, "No configuration found at: '#{path}'"
27
27
  end
28
28
  end
@@ -58,6 +58,14 @@ module Chozo
58
58
  f.write(self.to_json(pretty: true))
59
59
  end
60
60
  end
61
+
62
+ # Reload the current configuration file from disk
63
+ #
64
+ # @return [Chozo::Config::JSON]
65
+ def reload
66
+ mass_assign(self.class.from_file(path).attributes)
67
+ self
68
+ end
61
69
  end
62
70
  end
63
71
  end
@@ -1,110 +1,2 @@
1
- class Hash
2
- class << self
3
- # Create a new Hash containing other nested Hashes from a string containing
4
- # a dotted path. A Hash will be created and assigned to a key of another Hash
5
- # for each entry in the dotted path.
6
- #
7
- # If a value is provided for the optional seed argument then the value of the
8
- # deepest nested key will be set to the given value. If no value is provided
9
- # the value of the key will be nil.
10
- #
11
- # @example creating a nested hash from a dotted path
12
- #
13
- # Hash.from_dotted_path("deep.nested.hash") =>
14
- # {
15
- # "deep" => {
16
- # "nested" => {
17
- # "hash" => nil
18
- # }
19
- # }
20
- # }
21
- #
22
- #
23
- # @example specifying a seed value
24
- #
25
- # Hash.from_dotted_path("deep.nested.hash", :seed_value) =>
26
- # {
27
- # "deep" => {
28
- # "nested" => {
29
- # "hash" => :seed_value
30
- # }
31
- # }
32
- # }
33
- #
34
- # @param [String, Array] dotpath
35
- # @param [Object] seed
36
- # @param [Hash] target
37
- #
38
- # @return [Hash]
39
- def from_dotted_path(dotpath, seed = nil, target = self.new)
40
- case dotpath
41
- when String
42
- from_dotted_path(dotpath.split("."), seed)
43
- when Array
44
- if dotpath.empty?
45
- return target
46
- end
47
-
48
- key = dotpath.pop
49
-
50
- if target.empty?
51
- target[key] = seed
52
- from_dotted_path(dotpath, seed, target)
53
- else
54
- new_target = self.new
55
- new_target[key] = target
56
- from_dotted_path(dotpath, seed, new_target)
57
- end
58
- end
59
- end
60
- end
61
-
62
- # Return the value of the nested hash key from the given dotted path
63
- #
64
- # @example
65
- #
66
- # nested_hash = {
67
- # "deep" => {
68
- # "nested" => {
69
- # "hash" => :seed_value
70
- # }
71
- # }
72
- # }
73
- #
74
- # nested_hash.dig('deep.nested.hash') => :seed_value
75
- #
76
- # @param [String] path
77
- #
78
- # @return [Object, nil]
79
- def dig(path)
80
- parts = path.split('.', 2)
81
- match = (self[parts[0].to_s] || self[parts[0].to_sym])
82
- if !parts[1] or match.nil?
83
- match
84
- else
85
- match.dig(parts[1])
86
- end
87
- end
88
-
89
- # Returns an array of dotted paths from the keys, values of this Hash. Values which are
90
- # nested Hashes will also recurred into and their paths will be added properly.
91
- #
92
- # @param [Hash] source
93
- # @param [Array] acc
94
- # @param [Array] namespace
95
- #
96
- # @return [Array<String>]
97
- def dotted_paths(source = self, acc = Array.new, namespace = Array.new)
98
- if source.is_a?(Hash)
99
- source.each do |key, value|
100
- branch = namespace.dup
101
- branch << key
102
- dotted_paths(value, acc, branch)
103
- end
104
- else
105
- acc << namespace.join('.')
106
- end
107
-
108
- acc
109
- end
110
- end
1
+ require 'chozo/core_ext/hash/keys'
2
+ require 'chozo/core_ext/hash/dotted_paths'
@@ -0,0 +1,110 @@
1
+ class Hash
2
+ class << self
3
+ # Create a new Hash containing other nested Hashes from a string containing
4
+ # a dotted path. A Hash will be created and assigned to a key of another Hash
5
+ # for each entry in the dotted path.
6
+ #
7
+ # If a value is provided for the optional seed argument then the value of the
8
+ # deepest nested key will be set to the given value. If no value is provided
9
+ # the value of the key will be nil.
10
+ #
11
+ # @example creating a nested hash from a dotted path
12
+ #
13
+ # Hash.from_dotted_path("deep.nested.hash") =>
14
+ # {
15
+ # "deep" => {
16
+ # "nested" => {
17
+ # "hash" => nil
18
+ # }
19
+ # }
20
+ # }
21
+ #
22
+ #
23
+ # @example specifying a seed value
24
+ #
25
+ # Hash.from_dotted_path("deep.nested.hash", :seed_value) =>
26
+ # {
27
+ # "deep" => {
28
+ # "nested" => {
29
+ # "hash" => :seed_value
30
+ # }
31
+ # }
32
+ # }
33
+ #
34
+ # @param [String, Array] dotpath
35
+ # @param [Object] seed
36
+ # @param [Hash] target
37
+ #
38
+ # @return [Hash]
39
+ def from_dotted_path(dotpath, seed = nil, target = self.new)
40
+ case dotpath
41
+ when String
42
+ from_dotted_path(dotpath.split("."), seed)
43
+ when Array
44
+ if dotpath.empty?
45
+ return target
46
+ end
47
+
48
+ key = dotpath.pop
49
+
50
+ if target.empty?
51
+ target[key] = seed
52
+ from_dotted_path(dotpath, seed, target)
53
+ else
54
+ new_target = self.new
55
+ new_target[key] = target
56
+ from_dotted_path(dotpath, seed, new_target)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ # Return the value of the nested hash key from the given dotted path
63
+ #
64
+ # @example
65
+ #
66
+ # nested_hash = {
67
+ # "deep" => {
68
+ # "nested" => {
69
+ # "hash" => :seed_value
70
+ # }
71
+ # }
72
+ # }
73
+ #
74
+ # nested_hash.dig('deep.nested.hash') => :seed_value
75
+ #
76
+ # @param [String] path
77
+ #
78
+ # @return [Object, nil]
79
+ def dig(path)
80
+ parts = path.split('.', 2)
81
+ match = (self[parts[0].to_s] || self[parts[0].to_sym])
82
+ if !parts[1] or match.nil?
83
+ match
84
+ else
85
+ match.dig(parts[1])
86
+ end
87
+ end
88
+
89
+ # Returns an array of dotted paths from the keys, values of this Hash. Values which are
90
+ # nested Hashes will also recurred into and their paths will be added properly.
91
+ #
92
+ # @param [Hash] source
93
+ # @param [Array] acc
94
+ # @param [Array] namespace
95
+ #
96
+ # @return [Array<String>]
97
+ def dotted_paths(source = self, acc = Array.new, namespace = Array.new)
98
+ if source.is_a?(Hash)
99
+ source.each do |key, value|
100
+ branch = namespace.dup
101
+ branch << key
102
+ dotted_paths(value, acc, branch)
103
+ end
104
+ else
105
+ acc << namespace.join('.')
106
+ end
107
+
108
+ acc
109
+ end
110
+ end
@@ -0,0 +1,141 @@
1
+ # https://raw.github.com/rails/rails/master/activesupport/lib/active_support/core_ext/hash/keys.rb
2
+ #
3
+ # Replace with ActiveSupport 4.0 when released
4
+ class Hash
5
+ # Return a new hash with all keys converted using the block operation.
6
+ #
7
+ # hash = { name: 'Rob', age: '28' }
8
+ #
9
+ # hash.transform_keys{ |key| key.to_s.upcase }
10
+ # # => { "NAME" => "Rob", "AGE" => "28" }
11
+ def transform_keys
12
+ result = {}
13
+ each_key do |key|
14
+ result[yield(key)] = self[key]
15
+ end
16
+ result
17
+ end
18
+
19
+ # Destructively convert all keys using the block operations.
20
+ # Same as transform_keys but modifies +self+.
21
+ def transform_keys!
22
+ keys.each do |key|
23
+ self[yield(key)] = delete(key)
24
+ end
25
+ self
26
+ end
27
+
28
+ # Return a new hash with all keys converted to strings.
29
+ #
30
+ # hash = { name: 'Rob', age: '28' }
31
+ #
32
+ # hash.stringify_keys
33
+ # #=> { "name" => "Rob", "age" => "28" }
34
+ def stringify_keys
35
+ transform_keys{ |key| key.to_s }
36
+ end
37
+
38
+ # Destructively convert all keys to strings. Same as
39
+ # +stringify_keys+, but modifies +self+.
40
+ def stringify_keys!
41
+ transform_keys!{ |key| key.to_s }
42
+ end
43
+
44
+ # Return a new hash with all keys converted to symbols, as long as
45
+ # they respond to +to_sym+.
46
+ #
47
+ # hash = { 'name' => 'Rob', 'age' => '28' }
48
+ #
49
+ # hash.symbolize_keys
50
+ # #=> { name: "Rob", age: "28" }
51
+ def symbolize_keys
52
+ transform_keys{ |key| key.to_sym rescue key }
53
+ end
54
+ alias_method :to_options, :symbolize_keys
55
+
56
+ # Destructively convert all keys to symbols, as long as they respond
57
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
58
+ def symbolize_keys!
59
+ transform_keys!{ |key| key.to_sym rescue key }
60
+ end
61
+ alias_method :to_options!, :symbolize_keys!
62
+
63
+ # Validate all keys in a hash match <tt>*valid_keys</tt>, raising ArgumentError
64
+ # on a mismatch. Note that keys are NOT treated indifferently, meaning if you
65
+ # use strings for keys but assert symbols as keys, this will fail.
66
+ #
67
+ # { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
68
+ # { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: name"
69
+ # { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
70
+ def assert_valid_keys(*valid_keys)
71
+ valid_keys.flatten!
72
+ each_key do |k|
73
+ raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k)
74
+ end
75
+ end
76
+
77
+ # Return a new hash with all keys converted by the block operation.
78
+ # This includes the keys from the root hash and from all
79
+ # nested hashes.
80
+ #
81
+ # hash = { person: { name: 'Rob', age: '28' } }
82
+ #
83
+ # hash.deep_transform_keys{ |key| key.to_s.upcase }
84
+ # # => { "PERSON" => { "NAME" => "Rob", "AGE" => "28" } }
85
+ def deep_transform_keys(&block)
86
+ result = {}
87
+ each do |key, value|
88
+ result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
89
+ end
90
+ result
91
+ end
92
+
93
+ # Destructively convert all keys by using the block operation.
94
+ # This includes the keys from the root hash and from all
95
+ # nested hashes.
96
+ def deep_transform_keys!(&block)
97
+ keys.each do |key|
98
+ value = delete(key)
99
+ self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
100
+ end
101
+ self
102
+ end
103
+
104
+ # Return a new hash with all keys converted to strings.
105
+ # This includes the keys from the root hash and from all
106
+ # nested hashes.
107
+ #
108
+ # hash = { person: { name: 'Rob', age: '28' } }
109
+ #
110
+ # hash.deep_stringify_keys
111
+ # # => { "person" => { "name" => "Rob", "age" => "28" } }
112
+ def deep_stringify_keys
113
+ deep_transform_keys{ |key| key.to_s }
114
+ end
115
+
116
+ # Destructively convert all keys to strings.
117
+ # This includes the keys from the root hash and from all
118
+ # nested hashes.
119
+ def deep_stringify_keys!
120
+ deep_transform_keys!{ |key| key.to_s }
121
+ end
122
+
123
+ # Return a new hash with all keys converted to symbols, as long as
124
+ # they respond to +to_sym+. This includes the keys from the root hash
125
+ # and from all nested hashes.
126
+ #
127
+ # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
128
+ #
129
+ # hash.deep_symbolize_keys
130
+ # # => { person: { name: "Rob", age: "28" } }
131
+ def deep_symbolize_keys
132
+ deep_transform_keys{ |key| key.to_sym rescue key }
133
+ end
134
+
135
+ # Destructively convert all keys to symbols, as long as they respond
136
+ # to +to_sym+. This includes the keys from the root hash and from all
137
+ # nested hashes.
138
+ def deep_symbolize_keys!
139
+ deep_transform_keys!{ |key| key.to_sym rescue key }
140
+ end
141
+ end
@@ -0,0 +1,9 @@
1
+ module Hashie
2
+ # @author Jamie Winsor <jamie@vialstudios.com>
3
+ class Hash < ::Hash
4
+ # Ensure we always symbolize keys when calling #to_hash
5
+ def to_hash
6
+ super.deep_symbolize_keys
7
+ end
8
+ end
9
+ end
data/lib/chozo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Chozo
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chozo::Config::Abstract do
4
+ subject { Class.new(described_class).new }
5
+
6
+ describe "#to_hash" do
7
+ it "returns a Hash" do
8
+ subject.to_hash.should be_a(Hash)
9
+ end
10
+
11
+ it "contains all of the attributes" do
12
+ subject.attributes[:something] = "value"
13
+
14
+ subject.to_hash.should have_key(:something)
15
+ subject.to_hash[:something].should eql("value")
16
+ end
17
+ end
18
+
19
+ describe "#slice" do
20
+ before(:each) do
21
+ subject.attributes[:one] = {
22
+ nested: "value"
23
+ }
24
+ subject.attributes[:two] = {
25
+ nested: "other"
26
+ }
27
+ @sliced = subject.slice(:one)
28
+ end
29
+
30
+ it "returns a Hash" do
31
+ @sliced.should be_a(Hash)
32
+ end
33
+
34
+ it "contains just the sliced elements" do
35
+ @sliced.should have(1).item
36
+ end
37
+ end
38
+ end
@@ -102,4 +102,33 @@ describe Chozo::Config::JSON do
102
102
  }.should raise_error(Chozo::Errors::ConfigSaveError)
103
103
  end
104
104
  end
105
+
106
+ describe "#reload" do
107
+ before(:each) do
108
+ subject.path = tmp_path.join('tmpconfig.json').to_s
109
+ subject.save
110
+ end
111
+
112
+ it "returns self" do
113
+ subject.reload.should eql(subject)
114
+ end
115
+
116
+ it "updates the contents of self from disk" do
117
+ original = subject.class.from_file(subject.path)
118
+ subject.job = "programmer"
119
+ subject.save
120
+
121
+ original.job.should be_nil
122
+ original.reload
123
+ original.job.should eql("programmer")
124
+ end
125
+
126
+ it "raises ConfigNotFound if the path is nil" do
127
+ subject.path = nil
128
+
129
+ expect {
130
+ subject.reload.should eql(subject)
131
+ }.to raise_error(Chozo::Errors::ConfigNotFound)
132
+ end
133
+ end
105
134
  end
@@ -212,7 +212,7 @@ describe Chozo::VariaModel do
212
212
  subject.validate_required(model, key).first.should eql(:error)
213
213
  end
214
214
 
215
- it "passes validation if the value of the attribute is false", focus: true do
215
+ it "passes validation if the value of the attribute is false" do
216
216
  model.set_attribute(key, false)
217
217
 
218
218
  subject.validate_required(model, key).first.should eql(:ok)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chozo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.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-11-14 00:00:00.000000000 Z
12
+ date: 2012-12-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -82,10 +82,13 @@ files:
82
82
  - lib/chozo/core_ext.rb
83
83
  - lib/chozo/core_ext/boolean.rb
84
84
  - lib/chozo/core_ext/hash.rb
85
+ - lib/chozo/core_ext/hash/dotted_paths.rb
86
+ - lib/chozo/core_ext/hash/keys.rb
85
87
  - lib/chozo/core_ext/kernel.rb
86
88
  - lib/chozo/core_ext/set.rb
87
89
  - lib/chozo/errors.rb
88
90
  - lib/chozo/hashie_ext.rb
91
+ - lib/chozo/hashie_ext/hash.rb
89
92
  - lib/chozo/hashie_ext/mash.rb
90
93
  - lib/chozo/platform.rb
91
94
  - lib/chozo/ruby_engine.rb
@@ -95,13 +98,15 @@ files:
95
98
  - spec/spec_helper.rb
96
99
  - spec/support/helpers.rb
97
100
  - spec/support/matchers/each.rb
101
+ - spec/unit/chozo/config/abstract_spec.rb
98
102
  - spec/unit/chozo/config/json_spec.rb
99
103
  - spec/unit/chozo/core_ext/hash_spec.rb
100
104
  - spec/unit/chozo/platform_spec.rb
101
105
  - spec/unit/chozo/ruby_engine_spec.rb
102
106
  - spec/unit/chozo/varia_model_spec.rb
103
107
  homepage: https://github.com/reset/chozo
104
- licenses: []
108
+ licenses:
109
+ - Apache 2.0
105
110
  post_install_message:
106
111
  rdoc_options: []
107
112
  require_paths:
@@ -120,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
125
  version: '0'
121
126
  segments:
122
127
  - 0
123
- hash: 23954185641818190
128
+ hash: 3239723575146630686
124
129
  requirements: []
125
130
  rubyforge_project:
126
131
  rubygems_version: 1.8.23
@@ -132,6 +137,7 @@ test_files:
132
137
  - spec/spec_helper.rb
133
138
  - spec/support/helpers.rb
134
139
  - spec/support/matchers/each.rb
140
+ - spec/unit/chozo/config/abstract_spec.rb
135
141
  - spec/unit/chozo/config/json_spec.rb
136
142
  - spec/unit/chozo/core_ext/hash_spec.rb
137
143
  - spec/unit/chozo/platform_spec.rb