abyss 0.0.1
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/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +9 -0
- data/LICENSE +22 -0
- data/README.md +46 -0
- data/Rakefile +2 -0
- data/abyss.gemspec +19 -0
- data/lib/abyss.rb +20 -0
- data/lib/abyss/deep_store.rb +82 -0
- data/lib/abyss/errors.rb +19 -0
- data/lib/abyss/store.rb +34 -0
- data/lib/abyss/version.rb +3 -0
- data/spec/abyss/deep_store_spec.rb +116 -0
- data/spec/abyss/store_spec.rb +39 -0
- data/spec/spec_helper.rb +1 -0
- metadata +74 -0
data/.gitignore
ADDED
data/.rspec
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2012 Jesse Trimble
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Abyss
|
|
2
|
+
|
|
3
|
+
Ruby DSL for defining arbitrarily-deep configuration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
gem 'abyss'
|
|
10
|
+
|
|
11
|
+
And then execute:
|
|
12
|
+
|
|
13
|
+
$ bundle
|
|
14
|
+
|
|
15
|
+
Or install it yourself as:
|
|
16
|
+
|
|
17
|
+
$ gem install abyss
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Abyss.configure do
|
|
22
|
+
|
|
23
|
+
# An arbitrarily-named configuration group
|
|
24
|
+
#
|
|
25
|
+
rush do
|
|
26
|
+
|
|
27
|
+
# Define arbitrary properties
|
|
28
|
+
#
|
|
29
|
+
year_founded '1968'
|
|
30
|
+
members ["Geddy", "Alex", "Neil"]
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Accessing...
|
|
37
|
+
Abyss.configuration.rush.year_founded #=> "1968"
|
|
38
|
+
Abyss.configuration.rush.members #=> ["Geddy", "Alex", "Neil"]
|
|
39
|
+
|
|
40
|
+
## Contributing
|
|
41
|
+
|
|
42
|
+
1. Fork it
|
|
43
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
44
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
|
45
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
46
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/abyss.gemspec
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path('../lib/abyss/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |gem|
|
|
5
|
+
gem.authors = ["Jesse Trimble"]
|
|
6
|
+
gem.email = ["jesseltrimble@gmail.com"]
|
|
7
|
+
gem.description = %q{Manage arbitrarily-deep configurations through a friendly DSL.}
|
|
8
|
+
gem.summary = %q{Manage arbitrarily-deep configurations through a friendly DSL.}
|
|
9
|
+
gem.homepage = ""
|
|
10
|
+
|
|
11
|
+
gem.add_dependency "activesupport", '~> 3.2.0'
|
|
12
|
+
|
|
13
|
+
gem.files = `git ls-files`.split($\)
|
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
16
|
+
gem.name = "abyss"
|
|
17
|
+
gem.require_paths = ["lib"]
|
|
18
|
+
gem.version = Abyss::VERSION
|
|
19
|
+
end
|
data/lib/abyss.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "abyss/version"
|
|
2
|
+
require "abyss/errors"
|
|
3
|
+
require "abyss/deep_store"
|
|
4
|
+
require "abyss/store"
|
|
5
|
+
|
|
6
|
+
module Abyss
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
attr_accessor :configuration
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Public interface to Abyss Configuragion API
|
|
13
|
+
# See Store for examples.
|
|
14
|
+
#
|
|
15
|
+
def self.configure(&block)
|
|
16
|
+
self.configuration ||= Store.new
|
|
17
|
+
self.configuration.instance_eval &block
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'active_support/ordered_hash'
|
|
2
|
+
|
|
3
|
+
module Abyss
|
|
4
|
+
|
|
5
|
+
# = DeepStore
|
|
6
|
+
# === Abstract Class
|
|
7
|
+
#
|
|
8
|
+
# An object meant for configuration that allows arbitrary configuration
|
|
9
|
+
# properties and arbitrarily deep configuration groups.
|
|
10
|
+
#
|
|
11
|
+
# Meant to be subclassed. The power of this class lies in the 'assign'
|
|
12
|
+
# method.
|
|
13
|
+
#
|
|
14
|
+
# Examples:
|
|
15
|
+
#
|
|
16
|
+
# class MyConfig < DeepStore
|
|
17
|
+
#
|
|
18
|
+
# def assign(property_name, values)
|
|
19
|
+
# # values is an array of the arguments picked up by #method_missing
|
|
20
|
+
# self.configurations[property_name] = manipulate(values)
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# private
|
|
24
|
+
#
|
|
25
|
+
# def manipulate(values)
|
|
26
|
+
# # something important...
|
|
27
|
+
# values
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# my_config = MyConfig.new
|
|
33
|
+
# my_config.my_config_group do # arbitrary configuration group
|
|
34
|
+
# my_configuration_property "Hardy har!", "Grumblegrumblegrumble..." # configuration item, also arbitrary
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
# my_config.my_config_group.my_configuration_property #=> [ "Hardy har!", "Grumblegrumblegrumble..." ]
|
|
38
|
+
#
|
|
39
|
+
class DeepStore
|
|
40
|
+
|
|
41
|
+
attr_accessor :configurations
|
|
42
|
+
|
|
43
|
+
def initialize #:nodoc:
|
|
44
|
+
@configurations = ActiveSupport::OrderedHash.new {}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# If a block is passed, add a configuration group named `method_name`
|
|
48
|
+
# (which is just a new instance of DeepStore) and evaluate the block
|
|
49
|
+
# against the new instance.
|
|
50
|
+
#
|
|
51
|
+
# If one or more arguments are supplied, calls `#assign(method_name, args)
|
|
52
|
+
#
|
|
53
|
+
# If no arguments are supplied, return the entity stored by `method_name`.
|
|
54
|
+
# Could be a DeepStore instance or some arbitrary configuration.
|
|
55
|
+
#
|
|
56
|
+
def method_missing(method_name, *args, &block)
|
|
57
|
+
raise ArgumentError.new("Can't supply both a method argument and a block.") if block_given? && args.size > 0
|
|
58
|
+
|
|
59
|
+
if block_given?
|
|
60
|
+
@configurations[method_name] ||= self.class.new
|
|
61
|
+
@configurations[method_name].instance_eval &block
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
return get(method_name) if args.length == 0
|
|
65
|
+
|
|
66
|
+
assign(method_name, args)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Abstract method. Override this in a subclass to do processing on the
|
|
70
|
+
# config name / value to be stored.
|
|
71
|
+
#
|
|
72
|
+
def assign(name, values)
|
|
73
|
+
raise Errors::AbstractMethod.new("#assign")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def get(method_name) #:nodoc:
|
|
77
|
+
@configurations[method_name]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
data/lib/abyss/errors.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Abyss
|
|
2
|
+
|
|
3
|
+
module Errors
|
|
4
|
+
|
|
5
|
+
class AbstractMethod < RuntimeError
|
|
6
|
+
attr_accessor :name
|
|
7
|
+
|
|
8
|
+
def initialize(name)
|
|
9
|
+
self.name = name
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def message
|
|
13
|
+
"Abstract method: must override #{name} in a base class."
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
data/lib/abyss/store.rb
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Abyss
|
|
2
|
+
|
|
3
|
+
# = Store
|
|
4
|
+
#
|
|
5
|
+
# Utility for Abyss configuration.
|
|
6
|
+
# Intended for use within a host app's initializer, eg:
|
|
7
|
+
# /config/initializers/foundation.rb
|
|
8
|
+
#
|
|
9
|
+
# Examples:
|
|
10
|
+
#
|
|
11
|
+
# Abyss.configure do
|
|
12
|
+
# title 'Abyss Demo'
|
|
13
|
+
#
|
|
14
|
+
# backend do
|
|
15
|
+
# support do
|
|
16
|
+
# email 'info@factorylabs.com'
|
|
17
|
+
# phone '303-555-1234'
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
class Store < DeepStore
|
|
24
|
+
|
|
25
|
+
# Overrides DeepStore#assign. Simply assigns the configuration name to the
|
|
26
|
+
# first value.
|
|
27
|
+
#
|
|
28
|
+
def assign(name, values)
|
|
29
|
+
self.configurations[name] = values.first
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Abyss
|
|
4
|
+
|
|
5
|
+
describe ".configure" do
|
|
6
|
+
|
|
7
|
+
before { Abyss.configuration = nil }
|
|
8
|
+
|
|
9
|
+
it 'is shorthand for the Abyss Config API' do
|
|
10
|
+
expected_block = Proc.new { }
|
|
11
|
+
fake_config = mock()
|
|
12
|
+
Store.stub(:new).and_return(fake_config)
|
|
13
|
+
fake_config.should_receive(:instance_eval).with(&expected_block)
|
|
14
|
+
|
|
15
|
+
Abyss.configure &expected_block
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe DeepStore do
|
|
21
|
+
|
|
22
|
+
context "when dealing directly with an instance of DeepStore" do
|
|
23
|
+
|
|
24
|
+
subject { DeepStore.new }
|
|
25
|
+
|
|
26
|
+
describe "#initialize" do
|
|
27
|
+
|
|
28
|
+
it 'sets its #configurations to an empty OrderedHash' do
|
|
29
|
+
subject.configurations.should == ActiveSupport::OrderedHash.new
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "#get" do
|
|
35
|
+
|
|
36
|
+
it "returns what is stored in its #configurations" do
|
|
37
|
+
subject.configurations = { thing: 'foo' }
|
|
38
|
+
subject.get(:thing).should == 'foo'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe "#assign" do
|
|
44
|
+
|
|
45
|
+
it 'raises an error about subclassing' do
|
|
46
|
+
expect {
|
|
47
|
+
subject.some_nonexistent_method "foo"
|
|
48
|
+
}.to raise_error /must override #assign in a base class/i
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "#method_missing behavior" do
|
|
54
|
+
|
|
55
|
+
context "when given a block and no args" do
|
|
56
|
+
|
|
57
|
+
let(:config_mock) { mock }
|
|
58
|
+
let(:empty_proc) { proc {} }
|
|
59
|
+
|
|
60
|
+
before do
|
|
61
|
+
# force evaluation since we stub :new
|
|
62
|
+
subject
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "creates a new named configuration group" do
|
|
66
|
+
subject.some_undefined_method &empty_proc
|
|
67
|
+
subject.some_undefined_method.should be_instance_of subject.class
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "evaluates the block against a new configuration instance" do
|
|
71
|
+
DeepStore.stub(:new).and_return(config_mock)
|
|
72
|
+
config_mock.should_receive(:instance_eval).with &empty_proc
|
|
73
|
+
subject.some_undefined_method &empty_proc
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context "with no arguments and no block" do
|
|
79
|
+
|
|
80
|
+
it "returns a configuration stored by the method name" do
|
|
81
|
+
subject.should_receive(:get).with(:some_undefined_method)
|
|
82
|
+
subject.some_undefined_method
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context "with an argument" do
|
|
88
|
+
|
|
89
|
+
it "calls #assign on itself, passing the method name and args list" do
|
|
90
|
+
subject.should_receive(:assign).with(:some_undefined_method, ['foo'])
|
|
91
|
+
subject.some_undefined_method 'foo'
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe "invalid scenarios" do
|
|
97
|
+
|
|
98
|
+
context "with an argument and a block" do
|
|
99
|
+
|
|
100
|
+
it "raises an InvalidArguemnt error" do
|
|
101
|
+
expect {
|
|
102
|
+
subject.some_undefined_method("foo") {}
|
|
103
|
+
}.to raise_error ArgumentError, /can't supply both a method argument and a block/i
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Abyss
|
|
4
|
+
|
|
5
|
+
describe ".configure" do
|
|
6
|
+
|
|
7
|
+
before { Abyss.configuration = nil }
|
|
8
|
+
|
|
9
|
+
it 'is shorthand for the Abyss Store API' do
|
|
10
|
+
expected_block = Proc.new { }
|
|
11
|
+
fake_config = mock()
|
|
12
|
+
Store.stub(:new).and_return(fake_config)
|
|
13
|
+
fake_config.should_receive(:instance_eval).with(&expected_block)
|
|
14
|
+
|
|
15
|
+
Abyss.configure &expected_block
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe Store do
|
|
21
|
+
|
|
22
|
+
subject { Store.new }
|
|
23
|
+
|
|
24
|
+
it "is a subclass of DeepStore" do
|
|
25
|
+
subject.should be_a DeepStore
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "#assign" do
|
|
29
|
+
|
|
30
|
+
it "assigns the method name to the first passed value in #configurations" do
|
|
31
|
+
subject.assign("thing", ["foo"])
|
|
32
|
+
subject.configurations["thing"].should == "foo"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'abyss'
|
metadata
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: abyss
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Jesse Trimble
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-05-11 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: activesupport
|
|
16
|
+
requirement: &70310377219460 !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 3.2.0
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: *70310377219460
|
|
25
|
+
description: Manage arbitrarily-deep configurations through a friendly DSL.
|
|
26
|
+
email:
|
|
27
|
+
- jesseltrimble@gmail.com
|
|
28
|
+
executables: []
|
|
29
|
+
extensions: []
|
|
30
|
+
extra_rdoc_files: []
|
|
31
|
+
files:
|
|
32
|
+
- .gitignore
|
|
33
|
+
- .rspec
|
|
34
|
+
- Gemfile
|
|
35
|
+
- LICENSE
|
|
36
|
+
- README.md
|
|
37
|
+
- Rakefile
|
|
38
|
+
- abyss.gemspec
|
|
39
|
+
- lib/abyss.rb
|
|
40
|
+
- lib/abyss/deep_store.rb
|
|
41
|
+
- lib/abyss/errors.rb
|
|
42
|
+
- lib/abyss/store.rb
|
|
43
|
+
- lib/abyss/version.rb
|
|
44
|
+
- spec/abyss/deep_store_spec.rb
|
|
45
|
+
- spec/abyss/store_spec.rb
|
|
46
|
+
- spec/spec_helper.rb
|
|
47
|
+
homepage: ''
|
|
48
|
+
licenses: []
|
|
49
|
+
post_install_message:
|
|
50
|
+
rdoc_options: []
|
|
51
|
+
require_paths:
|
|
52
|
+
- lib
|
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
|
+
none: false
|
|
55
|
+
requirements:
|
|
56
|
+
- - ! '>='
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '0'
|
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
|
+
none: false
|
|
61
|
+
requirements:
|
|
62
|
+
- - ! '>='
|
|
63
|
+
- !ruby/object:Gem::Version
|
|
64
|
+
version: '0'
|
|
65
|
+
requirements: []
|
|
66
|
+
rubyforge_project:
|
|
67
|
+
rubygems_version: 1.8.10
|
|
68
|
+
signing_key:
|
|
69
|
+
specification_version: 3
|
|
70
|
+
summary: Manage arbitrarily-deep configurations through a friendly DSL.
|
|
71
|
+
test_files:
|
|
72
|
+
- spec/abyss/deep_store_spec.rb
|
|
73
|
+
- spec/abyss/store_spec.rb
|
|
74
|
+
- spec/spec_helper.rb
|