Skip to content

Commit

Permalink
convert to rspec
Browse files Browse the repository at this point in the history
  • Loading branch information
svenfuchs committed Oct 4, 2015
1 parent 6e5a1a7 commit 2d29a3d
Show file tree
Hide file tree
Showing 15 changed files with 268 additions and 213 deletions.
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
source 'https://rubygems.org'

gemspec

group :test do
gem 'rspec'
end
24 changes: 18 additions & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,28 @@ PATH
GEM
remote: https://rubygems.org/
specs:
minitest (5.3.4)
rake (0.9.2)
test_declarative (0.0.5)
diff-lcs (1.2.5)
rspec (3.3.0)
rspec-core (~> 3.3.0)
rspec-expectations (~> 3.3.0)
rspec-mocks (~> 3.3.0)
rspec-core (3.3.2)
rspec-support (~> 3.3.0)
rspec-expectations (3.3.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.3.0)
rspec-mocks (3.3.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.3.0)
rspec-support (3.3.0)

PLATFORMS
java
ruby

DEPENDENCIES
hashr!
minitest (>= 5.0.0)
rake
test_declarative (>= 0.0.2)
rspec

BUNDLED WITH
1.10.6
107 changes: 21 additions & 86 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,36 @@ It supports the following features:

Directly use Hashr instances like this:

config = Hashr.new('foo' => { 'bar' => 'bar' })
config = Hashr.new(foo: { bar: 'bar' })

config.foo? # => true
config.foo # => { :bar => 'bar' }
config.foo # => { bar: 'bar' }

config.foo.bar? # => true
config.foo.bar # => 'bar'

config.foo.bar = 'bar!'
config.foo.bar # => 'bar!'
config.foo.bar = 'bar'
config.foo.bar # => 'bar'

config.foo.baz = 'baz'
config.foo.baz # => 'baz'

Be aware that by default missing keys won't raise an exception but instead behave like Hash access:
Hash core methods are not available but assume you mean to look up keys with
the same name:

config = Hashr.new(count: 1, key: 'key')
config.count # => 1
config.key # => 'key'

In order to check a hash stored on a certain key you can convert it to a Ruby
Hash:

config = Hashr.new(count: 1, key: 'key')
config.to_h.count # => 2
config.to_h.key # => raises ArgumentError: "wrong number of arguments (0 for 1)"

By default missing keys won't raise an exception but instead behave like Hash
access:

config = Hashr.new
config.foo? # => false
Expand All @@ -43,76 +58,6 @@ You can make Hashr raise an `IndexError` though like this:
config.foo? # => false
config.foo # => raises an IndexError "Key :foo is not defined."

You can also anonymously overwrite core Hash methods like this:

config = Hashr.new(:count => 3) do
def count
self[:count]
end
end
config.count # => 3

And you can anonymously provide defaults like this:

data = { :foo => 'foo' }
defaults = { :bar => 'bar' }
config = Hashr.new(data, defaults)
config.foo # => 'foo'
config.bar # => 'bar'

But you can obvioulsy also derive a custom class to define defaults and overwrite core Hash methods like this:

class Config < Hashr
define :foo => { :bar => 'bar' }

def count
self[:count]
end
end

config = Config.new
config.foo.bar # => 'bar'

Include modules to nested hashes like this:

class Config < Hashr
module Boxes
def count
self[:count] # overwrites a Hash method to return the Hash's content here
end

def names
@names ||= (1..count).map { |num| "box-#{num}" }
end
end

define :boxes => { :count => 3, :_include => Boxes }
end

config = Config.new
config.boxes # => { :count => 3 }
config.boxes.count # => 3
config.boxes.names # => ["box-1", "box-2", "box-3"]

As overwriting Hash methods for method access to keys is a common pattern there's a short cut to it:

class Config < Hashr
define :_access => [:count, :key]
end

config = Config.new(:count => 3, :key => 'key')
config.count # => 3
config.key # => 'key'

Both `:_include` and `:_access` can be defined as defaults, i.e. so that they will be used on all nested hashes:

class Config < Hashr
default :_access => :key
end

config = Config.new(:key => 'key', :foo => { :key => 'foo.key' })
config.key # => 'key'
config.foo.key # => 'foo.key'

## Environment defaults

Expand All @@ -123,7 +68,7 @@ Hashr includes a simple module that makes it easy to overwrite configuration def

self.env_namespace = 'foo'

define :boxes => { :memory => '1024' }
define boxes: { memory: '1024' }
end

Now when an environment variable is defined then it will overwrite the default:
Expand All @@ -132,16 +77,6 @@ Now when an environment variable is defined then it will overwrite the default:
config = Config.new
config.boxes.memory # => '2048'

## Running the tests

You can run the tests as follows:

# going through bundler
bundle exec rake

# using just ruby
ruby -rubygems -Ilib:test test/hashr_test.rb

## Other libraries

You also might want to check out OpenStruct and Hashie.
Expand Down
4 changes: 0 additions & 4 deletions hashr.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,4 @@ Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.require_path = 'lib'
s.rubyforge_project = '[none]'

s.add_development_dependency 'rake'
s.add_development_dependency 'test_declarative', '>=0.0.2'
s.add_development_dependency 'minitest', '>=5.0.0'
end
36 changes: 36 additions & 0 deletions spec/core_ext/hash_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
describe Hash do
describe 'deep_symbolize_keys' do
it 'symbolizes keys on nested hashes' do
hash = { 'foo' => { 'bar' => 'bar' } }
expected = { :foo => { :bar => 'bar' } }
expect(hash.deep_symbolize_keys).to eq(expected)
end

it 'walks arrays' do
hash = { 'foo' => [{ 'bar' => 'bar', 'baz' => { 'buz' => 'buz' } }] }
expected = { :foo => [{ :bar => 'bar', :baz => { :buz => 'buz' } }] }
expect(hash.deep_symbolize_keys).to eq(expected)
end
end

describe 'deep_symbolize_keys!' do
it 'replaces with deep_symbolize' do
hash = { 'foo' => { 'bar' => 'baz' } }
expected = { :foo => { :bar => 'baz' } }
hash.deep_symbolize_keys!
expect(hash).to eq(expected)
end
end

describe 'slice' do
it 'returns a new hash containing the given keys' do
hash = { :foo => 'foo', :bar => 'bar', :baz => 'baz' }
expected = { :foo => 'foo', :bar => 'bar' }
expect(hash.slice(:foo, :bar)).to eq(expected)
end

it 'does not explode on a missing key' do
expect({}.slice(:foo)).to eq({})
end
end
end
27 changes: 27 additions & 0 deletions spec/hashr/conversion_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
describe Hashr do
shared_examples_for 'converts to a hash' do
it 'converts the Hashr instance to a hash' do
expect(hash.class).to eq(Hash)
end

it 'converts nested instances to hashes' do
expect(hash[:foo].class).to eq(Hash)
end

it 'populates the hash with symbolized keys' do
expect(hash[:foo][:bar]).to eq('baz')
end
end

let(:hashr) { Hashr.new(:foo => { :bar => 'baz' }) }

# describe 'to_h' do
# let(:hash) { hashr.to_h }
# include_examples 'converts to a hash'
# end

describe 'to_hash' do
let(:hash) { hashr.to_hash }
include_examples 'converts to a hash'
end
end
43 changes: 43 additions & 0 deletions spec/hashr/defaults_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
describe Hashr, 'defaults' do
shared_examples_for 'defaults' do |method|
describe 'using a symbolized hash' do
let(:klass) { Class.new(Hashr) { send method, foo: 'foo' } }

it 'defines the default' do
expect(klass.new.foo).to eq('foo')
end
end

describe 'using a stringified hash' do
let(:klass) { Class.new(Hashr) { send method, 'foo' => 'foo' } }

it 'defines the default' do
expect(klass.new.foo).to eq('foo')
end
end

describe 'with a nested hash' do
let(:klass) { Class.new(Hashr) { send method, foo: { bar: { baz: 'baz' } } } }

it 'defines the default' do
expect(klass.new.foo.bar.baz).to eq('baz')
end
end

describe 'with a nested array' do
let(:klass) { Class.new(Hashr) { send method, foo: ['bar'] } }

it 'defines the default' do
expect(klass.new.foo.first).to eq('bar')
end
end
end

# describe 'definition using default' do
# include_examples 'defaults', :default
# end

describe 'definition using define (deprecated)' do
include_examples 'defaults', :define
end
end
17 changes: 17 additions & 0 deletions spec/hashr/hash_acceess_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
describe Hashr, 'hash access' do
it 'is indifferent about symbols/strings (string data given, symbol keys used)' do
expect(Hashr.new('foo' => { 'bar' => 'bar' })[:foo][:bar]).to eq('bar')
end

it 'is indifferent about symbols/strings (symbol data given, string keys used)' do
expect(Hashr.new(foo: { bar: 'bar' })['foo']['bar']).to eq('bar')
end

# it 'allows accessing keys with Hash core method names (count)' do
# expect(Hashr.new(count: 2).count).to eq(2)
# end

# it 'allows accessing keys with Hash core method names (key)' do
# expect(Hashr.new(key: 'key').key).to eq('key')
# end
end
13 changes: 13 additions & 0 deletions spec/hashr/hash_assignment_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
describe Hashr, 'hash assignment' do
let(:hashr) { Hashr.new }

it 'works with a string key' do
hashr['foo'] = 'foo'
expect(hashr.foo).to eq('foo')
end

it 'works with a symbol key' do
hashr[:foo] = 'foo'
expect(hashr.foo).to eq('foo')
end
end
9 changes: 9 additions & 0 deletions spec/hashr/initialize_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
describe Hashr, 'initialize' do
it 'takes nil' do
expect { Hashr.new(nil) }.to_not raise_error
end

it 'raises an ArgumentError when given a string' do
expect { Hashr.new('foo') }.to raise_error(ArgumentError)
end
end
Loading

0 comments on commit 2d29a3d

Please sign in to comment.