bolts 0.1.0dev1
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/lib/bolts.rb +3 -0
- data/lib/bolts/application.rb +69 -0
- data/lib/bolts/settings.rb +7 -0
- data/lib/bolts/settings/container.rb +89 -0
- data/lib/bolts/settings/definition.rb +21 -0
- data/lib/bolts/settings/errors.rb +7 -0
- data/lib/bolts/settings/mixin.rb +58 -0
- data/lib/bolts/settings/registry.rb +104 -0
- data/lib/bolts/version.rb +3 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/unit/application_spec.rb +60 -0
- data/spec/unit/settings/container_spec.rb +68 -0
- data/spec/unit/settings/definition_spec.rb +35 -0
- data/spec/unit/settings/registry_spec.rb +95 -0
- metadata +80 -0
data/lib/bolts.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
module Bolts
|
2
|
+
class Application
|
3
|
+
|
4
|
+
# @!attribute [r] name
|
5
|
+
# @return [String]
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
# @!attribute [r] initializers
|
9
|
+
# @return [Array<Object>] A list of initializers to run before
|
10
|
+
# application startup
|
11
|
+
attr_reader :initializers
|
12
|
+
|
13
|
+
# @!attribute [r] finalizers
|
14
|
+
# @return [Array<Object>] A list of finalizers to run after application
|
15
|
+
# completion
|
16
|
+
attr_reader :finalizers
|
17
|
+
|
18
|
+
# @!attribute [r] error_handlers
|
19
|
+
# @return [Array<Object>] A list of erro handles to run in case of
|
20
|
+
# application errors.
|
21
|
+
attr_reader :error_handlers
|
22
|
+
|
23
|
+
def initialize(name)
|
24
|
+
@name = name
|
25
|
+
|
26
|
+
@main = nil
|
27
|
+
|
28
|
+
@initializers = []
|
29
|
+
@finalizers = []
|
30
|
+
|
31
|
+
@error_handlers = []
|
32
|
+
end
|
33
|
+
|
34
|
+
# Run the main body of the application
|
35
|
+
#
|
36
|
+
# This method takes a block that actually runs under the application,
|
37
|
+
# performs all initialization steps, runs the block, performs finalization
|
38
|
+
# steps, and runs error handlers if an error was raised.
|
39
|
+
#
|
40
|
+
# @return [void]
|
41
|
+
def run!
|
42
|
+
@initializers.each { |action| action.call(self) }
|
43
|
+
@main.call(self)
|
44
|
+
@finalizers.each { |action| action.call(self) }
|
45
|
+
rescue => e
|
46
|
+
@error_handlers.each { |action| action.call(self) }
|
47
|
+
raise e
|
48
|
+
end
|
49
|
+
|
50
|
+
# Add a new action to run on app initialization
|
51
|
+
def on_initialize(&block)
|
52
|
+
@initializers << block
|
53
|
+
end
|
54
|
+
|
55
|
+
# Add a new action to run on app finalization
|
56
|
+
def on_finalize(&block)
|
57
|
+
@finalizers << block
|
58
|
+
end
|
59
|
+
|
60
|
+
# Add a new action to run on app error
|
61
|
+
def on_error(&block)
|
62
|
+
@error_handlers << block
|
63
|
+
end
|
64
|
+
|
65
|
+
def on_run(&block)
|
66
|
+
@main = block
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'bolts/settings'
|
2
|
+
|
3
|
+
# Defines a collection for application settings
|
4
|
+
#
|
5
|
+
# This implements a hierarchical interface to application settings. Containers
|
6
|
+
# can define an optional parent container that will be used for default options
|
7
|
+
# if those options aren't set on the given container.
|
8
|
+
class Bolts::Settings::Container
|
9
|
+
|
10
|
+
# @!attribute [r] valid_keys
|
11
|
+
# @return [Set<Symbol>] All valid keys defined on the container or parent container.
|
12
|
+
attr_accessor :valid_keys
|
13
|
+
|
14
|
+
# @param parent [Bolts::Settings::Container] An optional parent container
|
15
|
+
def initialize(parent = nil)
|
16
|
+
@parent = parent
|
17
|
+
|
18
|
+
@valid_keys = Set.new
|
19
|
+
@settings = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Look up a value in the container. The lookup checks the current container,
|
23
|
+
# and then falls back to the parent container if it's given.
|
24
|
+
#
|
25
|
+
# @param key [Symbol] The lookup key
|
26
|
+
#
|
27
|
+
# @return [Object, nil] The retrieved value if present.
|
28
|
+
#
|
29
|
+
# @raise [Bolts::Settings::Container::InvalidKey] If the looked up key isn't
|
30
|
+
# a valid key.
|
31
|
+
def [](key)
|
32
|
+
validate_key! key
|
33
|
+
|
34
|
+
if @settings[key]
|
35
|
+
@settings[key]
|
36
|
+
elsif @parent and (pkey = @parent[key])
|
37
|
+
@settings[key] = pkey
|
38
|
+
pkey
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Set a value on the container
|
43
|
+
#
|
44
|
+
# @param key [Symbol] The lookup key
|
45
|
+
# @param value [Object] The value to store in the container
|
46
|
+
#
|
47
|
+
# @raise [Bolts::Settings::Container::InvalidKey] If the looked up key isn't
|
48
|
+
# a valid key.
|
49
|
+
def []=(key, value)
|
50
|
+
validate_key! key
|
51
|
+
|
52
|
+
@settings[key] = value
|
53
|
+
end
|
54
|
+
|
55
|
+
# Define a valid container key
|
56
|
+
#
|
57
|
+
# @note This should only be used by {#Bolts::Settings::ClassSettings}
|
58
|
+
#
|
59
|
+
# @param key [Symbol]
|
60
|
+
# @return [void]
|
61
|
+
def add_valid_key(key)
|
62
|
+
@valid_keys.add(key)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Determine if a key is a valid setting.
|
66
|
+
#
|
67
|
+
# @param key [Symbol]
|
68
|
+
#
|
69
|
+
# @return [true, false]
|
70
|
+
def valid_key?(key)
|
71
|
+
if @valid_keys.include?(key)
|
72
|
+
true
|
73
|
+
elsif @parent and @parent.valid_key?(key)
|
74
|
+
@valid_keys.add(key)
|
75
|
+
true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def validate_key!(key)
|
82
|
+
unless valid_key?(key)
|
83
|
+
raise InvalidKey, "Key #{key} is not a valid key"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# @api private
|
88
|
+
class InvalidKey < StandardError; end
|
89
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'bolts/settings'
|
2
|
+
|
3
|
+
class Bolts::Settings::Definition
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :desc
|
7
|
+
attr_reader :default
|
8
|
+
|
9
|
+
attr_writer :value
|
10
|
+
|
11
|
+
def initialize(name, desc, default)
|
12
|
+
|
13
|
+
@name = name
|
14
|
+
@desc = desc
|
15
|
+
@default = default
|
16
|
+
end
|
17
|
+
|
18
|
+
def value
|
19
|
+
(! @value.nil?) ? @value : @default
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'bolts/settings'
|
2
|
+
|
3
|
+
module Bolts::Settings::Mixin
|
4
|
+
|
5
|
+
def self.included(klass)
|
6
|
+
klass.send(:include, InstanceMethods)
|
7
|
+
klass.send(:extend, ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
|
12
|
+
# @return [Bolts::Settings::Container] A settings container for the given instance.
|
13
|
+
def settings
|
14
|
+
@settings ||= Bolts::Settings::Container.new(self.class.settings)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
|
20
|
+
# Bind to a setting registry so that global settings can change this class.
|
21
|
+
#
|
22
|
+
# @param registry [Bolts::Setting::Registry]
|
23
|
+
# @param name [String] The name of the setting to bind to
|
24
|
+
# @param block [Proc] An optional block to execute when the setting changes
|
25
|
+
def bind_setting(registry, name)
|
26
|
+
def_setting_attr(name)
|
27
|
+
|
28
|
+
registry.bind_watcher(self, name)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Define a setting and optional default on the extending class.
|
32
|
+
#
|
33
|
+
# @param key [Symbol]
|
34
|
+
# @param default [Object]
|
35
|
+
#
|
36
|
+
# @return [void]
|
37
|
+
def def_setting_attr(key, default = nil)
|
38
|
+
defaults.add_valid_key(key)
|
39
|
+
defaults[key] = default if default
|
40
|
+
end
|
41
|
+
|
42
|
+
# A singleton settings container for storing immutable default configuration
|
43
|
+
# on the extending class.
|
44
|
+
#
|
45
|
+
# @return [Bolts::Settings::Container]
|
46
|
+
def defaults
|
47
|
+
@defaults ||= Bolts::Settings::Container.new
|
48
|
+
end
|
49
|
+
|
50
|
+
# A singleton settings container for storing manual setting configurations
|
51
|
+
# on the extending class.
|
52
|
+
#
|
53
|
+
# @return [Bolts::Settings::Container]
|
54
|
+
def settings
|
55
|
+
@settings ||= Bolts::Settings::Container.new(defaults)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'bolts/settings'
|
2
|
+
require 'bolts/settings/definition'
|
3
|
+
|
4
|
+
class Bolts::Settings::Registry
|
5
|
+
|
6
|
+
attr_reader :definitions
|
7
|
+
|
8
|
+
attr_reader :watchers
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@definitions = []
|
12
|
+
|
13
|
+
@watchers = Hash.new { |h, k| h[k] = [] }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Create a new setting definition
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# reg.define_setting(
|
20
|
+
# 'my-setting',
|
21
|
+
# :desc => 'setting description goes here',
|
22
|
+
# :default => 'default value',
|
23
|
+
# )
|
24
|
+
#
|
25
|
+
# @param name [String] The setting name
|
26
|
+
# @param opts [Hash]
|
27
|
+
#
|
28
|
+
# @param opts [String] :desc The setting description
|
29
|
+
# @param opts [Object] :default
|
30
|
+
def define_setting(name, options)
|
31
|
+
definition = Bolts::Settings::Definition.new(name, options[:desc], options[:default])
|
32
|
+
@definitions << definition
|
33
|
+
end
|
34
|
+
|
35
|
+
# Look up the definition with the given name.
|
36
|
+
#
|
37
|
+
# @param name [String]
|
38
|
+
# @return [Bolts::Setting::Definition, nil]
|
39
|
+
def definition(name)
|
40
|
+
@definitions.find { |definition| name == definition.name }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Apply settings from a hash
|
44
|
+
#
|
45
|
+
# @param hash [Hash]
|
46
|
+
# @return [Hash] The hash with the processed values removed
|
47
|
+
def set_values(hash)
|
48
|
+
ret = hash.dup
|
49
|
+
|
50
|
+
hash.each_pair do |name, value|
|
51
|
+
if set_value(name, value)
|
52
|
+
ret.delete(name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
ret
|
57
|
+
end
|
58
|
+
|
59
|
+
# Set a definition value
|
60
|
+
#
|
61
|
+
# @param name [String]
|
62
|
+
# @param value [Object]
|
63
|
+
#
|
64
|
+
# @return [true, false] If the setting could be applied
|
65
|
+
def set_value(name, value)
|
66
|
+
if (setting_def = self.definition(name))
|
67
|
+
setting_def.value = value
|
68
|
+
true
|
69
|
+
else
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
alias :[]= :set_value
|
75
|
+
|
76
|
+
# Retrieve a definition value
|
77
|
+
#
|
78
|
+
# @param name [String]
|
79
|
+
#
|
80
|
+
# @return [Object]
|
81
|
+
def get_value(name)
|
82
|
+
if (setting_def = self.definition(name))
|
83
|
+
setting_def.value
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
alias :[] :get_value
|
88
|
+
|
89
|
+
# @param name [String] The setting name to bind to
|
90
|
+
# @param obj [#[]=] An object that can have properties set
|
91
|
+
def bind_watcher(name, settable)
|
92
|
+
@watchers[name] << settable
|
93
|
+
end
|
94
|
+
|
95
|
+
def notify_watchers
|
96
|
+
@watchers.each_pair do |name, list|
|
97
|
+
setting_def = self.definition(name)
|
98
|
+
|
99
|
+
list.each do |watcher|
|
100
|
+
watcher[name] = setting_def.value
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'bolts/application'
|
4
|
+
|
5
|
+
describe Bolts::Application do
|
6
|
+
let(:sequence) { [] }
|
7
|
+
subject do
|
8
|
+
described_class.new('test').tap do |app|
|
9
|
+
app.on_run { sequence << :main }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "with an initializer" do
|
14
|
+
it "hands the application to the initializer" do
|
15
|
+
subject.on_initialize { |app| expect(app).to eq subject }
|
16
|
+
subject.run!
|
17
|
+
end
|
18
|
+
|
19
|
+
it "runs the initializer before the main action" do
|
20
|
+
subject.on_initialize { sequence << :initializer }
|
21
|
+
subject.run!
|
22
|
+
|
23
|
+
expect(sequence).to eq [:initializer, :main]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "with a finalizer" do
|
28
|
+
it "hands the application to the finalizer" do
|
29
|
+
subject.on_finalize { |app| expect(app).to eq subject }
|
30
|
+
subject.run!
|
31
|
+
end
|
32
|
+
|
33
|
+
it "runs the finalizer after the main action" do
|
34
|
+
subject.on_finalize { sequence << :finalizer }
|
35
|
+
subject.run!
|
36
|
+
expect(sequence).to eq [:main, :finalizer]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "with an error handler" do
|
41
|
+
it "hands the application to the error handler" do
|
42
|
+
subject.on_error { |app| expect(app).to eq subject }
|
43
|
+
subject.on_run { raise "kaboom!" }
|
44
|
+
expect { subject.run! }.to raise_error StandardError, /kaboom!/
|
45
|
+
end
|
46
|
+
|
47
|
+
it "runs the error handler if an exception was raised" do
|
48
|
+
subject.on_error { sequence << :error }
|
49
|
+
subject.on_run { sequence << :main; raise "kaboom!" }
|
50
|
+
expect { subject.run! }.to raise_error StandardError, /kaboom!/
|
51
|
+
expect(sequence).to eq [:main, :error]
|
52
|
+
end
|
53
|
+
|
54
|
+
it "doesn't run the error handler on normal application exit" do
|
55
|
+
subject.on_error { sequence << :error }
|
56
|
+
subject.run!
|
57
|
+
expect(sequence).to eq [:main]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'bolts/settings'
|
4
|
+
|
5
|
+
describe Bolts::Settings::Container do
|
6
|
+
|
7
|
+
describe 'validating keys' do
|
8
|
+
it 'can add new valid keys' do
|
9
|
+
subject.add_valid_key(:v)
|
10
|
+
subject[:v]
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'can check if a key is valid' do
|
14
|
+
subject.add_valid_key(:v)
|
15
|
+
expect(subject.valid_key?(:v)).to be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'can list all valid keys' do
|
19
|
+
subject.add_valid_key(:v)
|
20
|
+
subject.add_valid_key(:w)
|
21
|
+
|
22
|
+
expect(subject.valid_keys).to include :v
|
23
|
+
expect(subject.valid_keys).to include :w
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'specifying settings' do
|
28
|
+
it 'fails if a setting application uses an invalid key' do
|
29
|
+
expect { subject[:invalid] = 'fail' }.to raise_error Bolts::Settings::Container::InvalidKey
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'can look up values that it sets' do
|
33
|
+
subject.add_valid_key :v
|
34
|
+
subject[:v] = 'set'
|
35
|
+
expect(subject[:v]).to eq 'set'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'looking up settings' do
|
40
|
+
before do
|
41
|
+
subject.add_valid_key :v
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'fails if a setting lookup uses an invalid key' do
|
45
|
+
expect { subject[:invalid] }.to raise_error Bolts::Settings::Container::InvalidKey
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns nil if a key is valid but no setting is present' do
|
49
|
+
expect(subject[:v]).to be_nil
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'with a parent container' do
|
53
|
+
let(:parent) { described_class.new.tap { |p| p.add_valid_key :v } }
|
54
|
+
subject { described_class.new(parent) }
|
55
|
+
|
56
|
+
it 'uses its setting over a parent value' do
|
57
|
+
subject[:v] = 'child'
|
58
|
+
parent[:v] = 'parent'
|
59
|
+
expect(subject[:v]).to eq 'child'
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'falls back to the parent value if it does not have a value' do
|
63
|
+
parent[:v] = 'parent'
|
64
|
+
expect(subject[:v]).to eq 'parent'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'bolts/settings/definition'
|
3
|
+
|
4
|
+
describe Bolts::Settings::Definition do
|
5
|
+
|
6
|
+
subject do
|
7
|
+
described_class.new(
|
8
|
+
'test',
|
9
|
+
'description here',
|
10
|
+
'default value'
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "has a name" do
|
15
|
+
expect(subject.name).to eq 'test'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "has a description" do
|
19
|
+
expect(subject.desc).to eq 'description here'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "has a default value" do
|
23
|
+
expect(subject.default).to eq 'default value'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "prefers an explicit value over a default value" do
|
27
|
+
subject.value = 'explicit!'
|
28
|
+
expect(subject.value).to eq 'explicit!'
|
29
|
+
end
|
30
|
+
|
31
|
+
it "uses a default value if no explicit value is specified" do
|
32
|
+
subject.value = nil
|
33
|
+
expect(subject.value).to eq 'default value'
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'bolts/settings/registry'
|
3
|
+
|
4
|
+
describe Bolts::Settings::Registry do
|
5
|
+
|
6
|
+
it "can define new settings" do
|
7
|
+
subject.define_setting('something', :desc => 'a setting definition!')
|
8
|
+
expect(subject.definitions).to have(1).items
|
9
|
+
expect(subject.definition('something')).to be_a_kind_of Bolts::Settings::Definition
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "applying settings" do
|
13
|
+
before do
|
14
|
+
subject.define_setting('partycat', :desc => 'party cat loves to party')
|
15
|
+
subject.define_setting('partydog', :desc => 'party dog also loves to party')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "applies settings from a hash" do
|
19
|
+
settings = {
|
20
|
+
'partycat' => 'parties!',
|
21
|
+
'partydog' => 'we love parties!',
|
22
|
+
}
|
23
|
+
|
24
|
+
subject.set_values(settings)
|
25
|
+
|
26
|
+
expect(subject.definition('partycat').value).to eq 'parties!'
|
27
|
+
expect(subject.definition('partydog').value).to eq 'we love parties!'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can directly retrieve a definition value" do
|
31
|
+
settings = {
|
32
|
+
'partycat' => 'parties!',
|
33
|
+
'partydog' => 'we love parties!',
|
34
|
+
}
|
35
|
+
|
36
|
+
subject.set_values(settings)
|
37
|
+
|
38
|
+
expect(subject.get_value('partycat')).to eq 'parties!'
|
39
|
+
expect(subject.get_value('partydog')).to eq 'we love parties!'
|
40
|
+
end
|
41
|
+
|
42
|
+
it "removes used settings from the returned hash" do
|
43
|
+
input = {
|
44
|
+
'partycat' => 'parties!',
|
45
|
+
'partydog' => 'we love parties!',
|
46
|
+
'partysnake' => 'partysnake hates parties'
|
47
|
+
}
|
48
|
+
|
49
|
+
output = subject.set_values(input)
|
50
|
+
|
51
|
+
expect(output).to have(1).items
|
52
|
+
expect(output).to include('partysnake' => 'partysnake hates parties')
|
53
|
+
end
|
54
|
+
|
55
|
+
it "doesn't modify the hash in place" do
|
56
|
+
input = {
|
57
|
+
'partycat' => 'parties!',
|
58
|
+
'partydog' => 'we love parties!',
|
59
|
+
'partysnake' => 'partysnake hates parties'
|
60
|
+
}
|
61
|
+
|
62
|
+
subject.set_values(input)
|
63
|
+
|
64
|
+
expect(input).to eq input
|
65
|
+
end
|
66
|
+
|
67
|
+
it "applies a single setting and value" do
|
68
|
+
subject.set_value('partycat', 'parties!')
|
69
|
+
expect(subject.definition('partycat').value).to eq 'parties!'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "binding values" do
|
74
|
+
let(:container) { double('settings container') }
|
75
|
+
|
76
|
+
before do
|
77
|
+
subject.define_setting('partycat', :desc => 'party cat loves to party')
|
78
|
+
subject.set_value('partycat', 'parties!')
|
79
|
+
end
|
80
|
+
|
81
|
+
it "can bind objects to settings" do
|
82
|
+
subject.bind_watcher('partycat', container)
|
83
|
+
|
84
|
+
expect(subject.watchers).to include('partycat' => [container])
|
85
|
+
end
|
86
|
+
|
87
|
+
it "can notify bound objects" do
|
88
|
+
subject.bind_watcher('partycat', container)
|
89
|
+
|
90
|
+
expect(container).to receive(:[]=).with('partycat', 'parties!')
|
91
|
+
|
92
|
+
subject.notify_watchers
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bolts
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0dev1
|
5
|
+
prerelease: 5
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Adrien Thebo
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-12-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.14.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.14.0
|
30
|
+
description:
|
31
|
+
email: adrien@somethingsinistral.net
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- lib/bolts/settings.rb
|
37
|
+
- lib/bolts/settings/errors.rb
|
38
|
+
- lib/bolts/settings/registry.rb
|
39
|
+
- lib/bolts/settings/container.rb
|
40
|
+
- lib/bolts/settings/mixin.rb
|
41
|
+
- lib/bolts/settings/definition.rb
|
42
|
+
- lib/bolts/version.rb
|
43
|
+
- lib/bolts/application.rb
|
44
|
+
- lib/bolts.rb
|
45
|
+
- spec/spec_helper.rb
|
46
|
+
- spec/unit/settings/registry_spec.rb
|
47
|
+
- spec/unit/settings/container_spec.rb
|
48
|
+
- spec/unit/settings/definition_spec.rb
|
49
|
+
- spec/unit/application_spec.rb
|
50
|
+
homepage: http://github.com/adrienthebo/bolts
|
51
|
+
licenses:
|
52
|
+
- Apache 2.0
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>'
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.3.1
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 1.8.23
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: Bolts is a foundation for writing applications
|
75
|
+
test_files:
|
76
|
+
- spec/unit/settings/registry_spec.rb
|
77
|
+
- spec/unit/settings/container_spec.rb
|
78
|
+
- spec/unit/settings/definition_spec.rb
|
79
|
+
- spec/unit/application_spec.rb
|
80
|
+
has_rdoc:
|