chozo 0.2.3 → 0.3.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/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