hashr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ hashr (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ test_declarative (0.0.5)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ hashr!
16
+ test_declarative (>= 0.0.2)
data/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'lib' << 'test'
6
+ t.pattern = 'test/**/*_test.rb'
7
+ t.verbose = false
8
+ end
9
+
10
+ task :default => :test
data/lib/hashr.rb ADDED
@@ -0,0 +1,61 @@
1
+ class Hashr < Hash
2
+ autoload :EnvDefaults, 'hashr/env_defaults'
3
+
4
+ TEMPLATE = new
5
+
6
+ class << self
7
+ def define(definition)
8
+ @definition = definition
9
+ end
10
+
11
+ def definition
12
+ @definition ||= {}
13
+ end
14
+ end
15
+
16
+ def initialize(data = {})
17
+ replace(deep_includize(deep_hasherize(deep_merge(self.class.definition, data))))
18
+ end
19
+
20
+ def []=(key, value)
21
+ super(key, value.is_a?(Hash) ? self.class.new(value) : value)
22
+ end
23
+
24
+ def respond_to?(name)
25
+ true
26
+ end
27
+
28
+ def method_missing(name, *args, &block)
29
+ case name.to_s[-1]
30
+ when '?'
31
+ !!self[name.to_s[0..-2].to_sym]
32
+ when '='
33
+ self[name.to_s[0..-2].to_sym] = args.first
34
+ else
35
+ self[name]
36
+ end
37
+ end
38
+
39
+ protected
40
+
41
+ def deep_merge(left, right)
42
+ merger = proc { |key, v1, v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? self.class.new(v1.merge(v2, &merger)) : v2 }
43
+ left.merge(right || {}, &merger)
44
+ end
45
+
46
+ def deep_hasherize(hash)
47
+ hash.inject(TEMPLATE.dup) do |result, (key, value)|
48
+ result.merge(key.to_sym => value.is_a?(Hash) ? deep_hasherize(value) : value)
49
+ end
50
+ end
51
+
52
+ def deep_includize(hash)
53
+ if modules = hash.delete(:_include)
54
+ meta_class = (class << hash; self end)
55
+ Array(modules).each { |mod| meta_class.send(:include, mod) }
56
+ end
57
+ hash.inject(hash) do |hash, (key, value)|
58
+ hash.merge(key => value.is_a?(Hash) ? deep_includize(value) : value)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,21 @@
1
+ class Hashr < Hash
2
+ module EnvDefaults
3
+ def definition
4
+ deep_enverize(super)
5
+ end
6
+
7
+ protected
8
+
9
+ def deep_enverize(hash, nesting = ['WORKER'])
10
+ hash.each do |key, value|
11
+ nesting << key.to_s.upcase
12
+ hash[key] = case value
13
+ when Hash
14
+ deep_enverize(value, nesting)
15
+ else
16
+ ENV.fetch(nesting.join('_'), value)
17
+ end.tap { nesting.pop }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ class Hashr < Hash
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,63 @@
1
+ require 'test_helper'
2
+
3
+ class HashrTest < Test::Unit::TestCase
4
+ def teardown
5
+ ENV.keys.select { |key| key =~ /^WORKER_/ }.each { |key| ENV.delete(key) }
6
+ end
7
+
8
+ test 'method access on an existing key returns the value' do
9
+ assert_equal 'foo', Hashr.new({ :foo => 'foo' }).foo
10
+ end
11
+
12
+ test 'method access on a non-existing key returns nil' do
13
+ assert_nil Hashr.new({ :foo => 'foo' }).bar
14
+ end
15
+
16
+ test 'method access on an existing nested key returns the value' do
17
+ assert_equal 'bar', Hashr.new({ :foo => { :bar => 'bar' } }).foo.bar
18
+ end
19
+
20
+ test 'method access on a non-existing nested key returns nil' do
21
+ assert_nil Hashr.new({ :foo => { :bar => 'bar' } }).foo.baz
22
+ end
23
+
24
+ test 'method access with a question mark returns true if the key has a value' do
25
+ assert_equal true, Hashr.new({ :foo => { :bar => 'bar' } }).foo.bar?
26
+ end
27
+
28
+ test 'method access with a question mark returns false if the key does not have a value' do
29
+ assert_equal false, Hashr.new({ :foo => { :bar => 'bar' } }).foo.baz?
30
+ end
31
+
32
+ test 'method assignment works' do
33
+ hashr = Hashr.new
34
+ hashr.foo = 'foo'
35
+ assert_equal 'foo', hashr.foo
36
+ end
37
+
38
+ test 'defining defaults' do
39
+ klass = Class.new(Hashr)
40
+ klass.define(:foo => 'foo', :bar => { :baz => 'baz' })
41
+ assert_equal 'foo', klass.new.foo
42
+ assert_equal 'baz', klass.new.bar.baz
43
+ end
44
+
45
+ test 'defaults to env vars' do
46
+ klass = Class.new(Hashr)
47
+ klass.extend Hashr::EnvDefaults
48
+ klass.define(:foo => 'foo', :bar => { :baz => 'baz' })
49
+
50
+ ENV['WORKER_FOO'] = 'env foo'
51
+ ENV['WORKER_BAR_BAZ'] = 'env bar baz'
52
+
53
+ assert_equal 'env foo', klass.new.foo
54
+ assert_equal 'env bar baz', klass.new.bar.baz
55
+ end
56
+
57
+ test 'a key :_include includes the given modules' do
58
+ klass = Class.new(Hashr)
59
+ klass.define(:foo => { :_include => Module.new { def helper; 'helper'; end } })
60
+ assert_equal 'helper', klass.new.foo.helper
61
+ end
62
+ end
63
+
@@ -0,0 +1,4 @@
1
+ require 'bundler/setup'
2
+ require 'test/unit'
3
+ require 'test_declarative'
4
+ require 'hashr'
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hashr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sven Fuchs
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-07-23 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: test_declarative
17
+ requirement: &2165879540 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 0.0.2
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2165879540
26
+ description: Simple Hash extension targetted at configuration.
27
+ email: svenfuchs@artweb-design.de
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - lib/hashr/env_defaults.rb
33
+ - lib/hashr/version.rb
34
+ - lib/hashr.rb
35
+ - test/hashr_test.rb
36
+ - test/test_helper.rb
37
+ - Gemfile
38
+ - Gemfile.lock
39
+ - Rakefile
40
+ - README
41
+ has_rdoc: true
42
+ homepage: http://github.com/svenfuchs/hashr
43
+ licenses: []
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project: ! '[none]'
62
+ rubygems_version: 1.6.2
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: Simple Hash extension targetted at configuration
66
+ test_files: []