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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in abyss.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rspec'
8
+ gem 'autotest'
9
+ end
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.
@@ -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
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -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
@@ -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
@@ -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
@@ -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,3 @@
1
+ module Abyss
2
+ VERSION = "0.0.1"
3
+ 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
@@ -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