simonmenke-ec 0.0.2
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/LICENSE.txt +22 -0
- data/README.textile +0 -0
- data/lib/ec/list_specification.rb +73 -0
- data/lib/ec/macros.rb +57 -0
- data/lib/ec/map_specification.rb +79 -0
- data/lib/ec/specification.rb +44 -0
- data/lib/ec/store.rb +54 -0
- data/lib/ec.rb +12 -0
- data/test/list_specification_test.rb +71 -0
- data/test/map_specification_test.rb +57 -0
- data/test/specification_test.rb +28 -0
- data/test/store_test.rb +65 -0
- data/test/test_helper.rb +55 -0
- data/test/update_test.rb +65 -0
- metadata +71 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2009 Simon Menke
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
File without changes
|
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
module EC
|
3
|
+
|
4
|
+
class ListSpecification < Specification
|
5
|
+
|
6
|
+
attr_accessor :child # :nodoc:
|
7
|
+
attr_accessor :update_policy # :nodoc:
|
8
|
+
|
9
|
+
def initialize(name=:root, parent=nil, &block) # :nodoc:
|
10
|
+
@child = nil
|
11
|
+
@update_policy = :merge
|
12
|
+
super(name, parent) do |spec|
|
13
|
+
spec.should_be_a Array
|
14
|
+
block.call(spec) if block
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def process(value, parent=nil, path=[:root]) # :nodoc:
|
19
|
+
@processors.each do |processor|
|
20
|
+
processor.call(self, value, parent, path)
|
21
|
+
end
|
22
|
+
value.each_with_index do |v , idx|
|
23
|
+
@child.process(v, value, path + [idx])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# specify a list as the list element
|
28
|
+
def list(&block)
|
29
|
+
@child ||= EC::ListSpecification.new(:item, self)
|
30
|
+
block.call(@child)
|
31
|
+
end
|
32
|
+
|
33
|
+
# specify a terminal node as the list element
|
34
|
+
def conf(&block)
|
35
|
+
@child = EC::Specification.new(:item, self)
|
36
|
+
block.call(@child)
|
37
|
+
end
|
38
|
+
|
39
|
+
# specify a map as the list element
|
40
|
+
def map(&block)
|
41
|
+
@child = EC::MapSpecification.new(:item, self)
|
42
|
+
block.call(@child)
|
43
|
+
end
|
44
|
+
|
45
|
+
# set the update policy
|
46
|
+
def on_update(policy)
|
47
|
+
unless [:merger, :replace].include? policy
|
48
|
+
raise SpecificationError, "EC supports only :merge and :replace policies"
|
49
|
+
end
|
50
|
+
@update_policy = policy
|
51
|
+
end
|
52
|
+
|
53
|
+
def update(base, delta) # :nodoc:
|
54
|
+
case @update_policy
|
55
|
+
when :merge then merge(base, delta)
|
56
|
+
when :replace then replace(base, delta)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def merge(base, delta) # :nodoc:
|
61
|
+
result = []
|
62
|
+
result += base if base
|
63
|
+
result += delta if delta
|
64
|
+
result if base and delta
|
65
|
+
end
|
66
|
+
|
67
|
+
def replace(base, delta) # :nodoc:
|
68
|
+
delta == nil ? base : delta
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
data/lib/ec/macros.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
module EC
|
3
|
+
|
4
|
+
class ValidationError < StandardError ; end
|
5
|
+
class SpecificationError < StandardError ; end
|
6
|
+
|
7
|
+
module Macros
|
8
|
+
|
9
|
+
# Add a processor
|
10
|
+
def processor(&block)
|
11
|
+
@processors << block
|
12
|
+
end
|
13
|
+
|
14
|
+
# Raise unless this spec is present in the parent
|
15
|
+
def should_be_present
|
16
|
+
unless parent.is_a? MapSpecification
|
17
|
+
raise SpecificationError, "#{pretty_path(parent.path)} needs to be of type Map"
|
18
|
+
end
|
19
|
+
parent.processor do |spec, value, parent, path|
|
20
|
+
unless value.include? self.name.to_sym
|
21
|
+
raise ValidationError, "#{pretty_path(path)} needs a #{self.name.inspect} entry"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Raise unless this spec is of type <tt>type</tt>
|
27
|
+
def should_be_a(type)
|
28
|
+
processor do |spec, value, parent, path|
|
29
|
+
unless value.is_a? type
|
30
|
+
raise ValidationError, "#{pretty_path(path)} needs to be a #{type.inspect}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Raise if this spec is empty
|
36
|
+
def should_not_be_empty
|
37
|
+
processor do |spec, value, parent, path|
|
38
|
+
empty = if value.respond_to? :empty?
|
39
|
+
value.empty?
|
40
|
+
elsif value.respond_to? :count
|
41
|
+
value.count == 0
|
42
|
+
elsif value.respond_to? :size
|
43
|
+
value.size == 0
|
44
|
+
elsif value.respond_to? :length
|
45
|
+
value.length == 0
|
46
|
+
else
|
47
|
+
raise ValidationError, "#{pretty_path(path)} doesn't respond to :empty?, :count, :size or :length"
|
48
|
+
end
|
49
|
+
if empty
|
50
|
+
raise ValidationError, "#{pretty_path(path)} must not be empty."
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
|
2
|
+
module EC
|
3
|
+
|
4
|
+
class MapSpecification < Specification
|
5
|
+
|
6
|
+
attr_accessor :children # :nodoc:
|
7
|
+
attr_accessor :update_policy # :nodoc:
|
8
|
+
|
9
|
+
def initialize(name=:root, parent=nil, &block) # :nodoc:
|
10
|
+
@children = {}
|
11
|
+
@update_policy = :merge
|
12
|
+
super(name, parent) do |spec|
|
13
|
+
spec.should_be_a Hash
|
14
|
+
block.call(spec) if block
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def process(value, parent=nil, path=[:root]) # :nodoc:
|
19
|
+
@processors.each do |processor|
|
20
|
+
processor.call(self, value, parent, path)
|
21
|
+
end
|
22
|
+
@children.each do |k,v|
|
23
|
+
v.process(value[k], value, path + [k]) if value.include? k
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# specify a list with key name.
|
28
|
+
def list(name, &block)
|
29
|
+
@children[name.to_sym] ||= EC::ListSpecification.new(name, self)
|
30
|
+
block.call(@children[name.to_sym])
|
31
|
+
end
|
32
|
+
|
33
|
+
# specify a terminal node with key name.
|
34
|
+
def conf(name, &block)
|
35
|
+
@children[name.to_sym] ||= EC::Specification.new(name, self)
|
36
|
+
block.call(@children[name.to_sym])
|
37
|
+
end
|
38
|
+
|
39
|
+
# specify a map with key name.
|
40
|
+
def map(name, &block)
|
41
|
+
@children[name.to_sym] ||= EC::MapSpecification.new(name, self)
|
42
|
+
block.call(@children[name.to_sym])
|
43
|
+
end
|
44
|
+
|
45
|
+
# set the update policy
|
46
|
+
def on_update(policy)
|
47
|
+
unless [:merger, :replace].include? policy
|
48
|
+
raise SpecificationError, "EC supports only :merge and :replace policies"
|
49
|
+
end
|
50
|
+
@update_policy = policy
|
51
|
+
end
|
52
|
+
|
53
|
+
def update(base, delta) # :nodoc:
|
54
|
+
case @update_policy
|
55
|
+
when :merge then merge(base, delta)
|
56
|
+
when :replace then replace(base, delta)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def merge(base, delta) # :nodoc:
|
61
|
+
result = (base || {}).dup
|
62
|
+
delta.each do |k,v|
|
63
|
+
key = k.to_sym
|
64
|
+
if @children[key]
|
65
|
+
result[key] = @children[key].update(result[key], v)
|
66
|
+
else
|
67
|
+
result[key] = v
|
68
|
+
end
|
69
|
+
end
|
70
|
+
result
|
71
|
+
end
|
72
|
+
|
73
|
+
def replace(base, delta) # :nodoc:
|
74
|
+
delta == nil ? base : delta
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
module EC
|
3
|
+
|
4
|
+
class Specification
|
5
|
+
|
6
|
+
include Macros
|
7
|
+
|
8
|
+
# the name/key of this specification
|
9
|
+
attr_accessor :name
|
10
|
+
# the parent of this specification
|
11
|
+
attr_accessor :parent
|
12
|
+
attr_accessor :processors # :nodoc:
|
13
|
+
|
14
|
+
def initialize(name=:root, parent=nil, &block) # :nodoc:
|
15
|
+
@name = name
|
16
|
+
@parent = parent
|
17
|
+
@processors = []
|
18
|
+
block.call(self) if block
|
19
|
+
end
|
20
|
+
|
21
|
+
def process(value, parent=nil, path=[:root]) # :nodoc:
|
22
|
+
@processors.each do |processor|
|
23
|
+
processor.call(self, value, parent, path)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def update(base, delta) # :nodoc:
|
28
|
+
delta == nil ? base : delta
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def pretty_path(path) # :nodoc:
|
34
|
+
path.collect do |component|
|
35
|
+
case component
|
36
|
+
when Symbol, String then ".#{component}"
|
37
|
+
when Fixnum then "[#{component}]"
|
38
|
+
end
|
39
|
+
end.join().sub(/^\./, '')
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/ec/store.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
module EC
|
3
|
+
|
4
|
+
class Store
|
5
|
+
|
6
|
+
attr_accessor :specification
|
7
|
+
|
8
|
+
# pass a block to specify this store
|
9
|
+
def initialize(&block)
|
10
|
+
specify &block
|
11
|
+
@data = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
# edit this stores specifictaion
|
15
|
+
def specify(&block)
|
16
|
+
@specification ||= EC::MapSpecification.new
|
17
|
+
block.call(@specification) if block
|
18
|
+
@specification
|
19
|
+
end
|
20
|
+
|
21
|
+
# reset the date in this store. When you pass true the specifictaion will be reset too.
|
22
|
+
def reset!(clear_specification=false)
|
23
|
+
@data = nil
|
24
|
+
@specification = nil if clear_specification
|
25
|
+
end
|
26
|
+
|
27
|
+
# configre this store with a ruby object. The root must be a Hash.
|
28
|
+
def configure_with_ruby(ruby)
|
29
|
+
@data = @specification.update(@data, ruby)
|
30
|
+
end
|
31
|
+
|
32
|
+
# configre this store with a YAML file.
|
33
|
+
def configure_with_yaml(path)
|
34
|
+
configure_with_ruby YAML.load_file(path)
|
35
|
+
end
|
36
|
+
|
37
|
+
# validate this store. This method will raise a EC::ValidationError when the store is invalid
|
38
|
+
def validate
|
39
|
+
@specification.process(@data)
|
40
|
+
end
|
41
|
+
|
42
|
+
# access the data in this store.
|
43
|
+
def config
|
44
|
+
@data || {}
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
# access the global store.
|
50
|
+
def self.store
|
51
|
+
@__store = EC::Store.new
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/ec.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module EC
|
5
|
+
|
6
|
+
end
|
7
|
+
|
8
|
+
require File.dirname(__FILE__)+'/ec/store'
|
9
|
+
require File.dirname(__FILE__)+'/ec/macros'
|
10
|
+
require File.dirname(__FILE__)+'/ec/specification'
|
11
|
+
require File.dirname(__FILE__)+'/ec/map_specification'
|
12
|
+
require File.dirname(__FILE__)+'/ec/list_specification'
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class ListSpecificationTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "ListSpecification" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
|
9
|
+
@spec = EC::ListSpecification.new do |list|
|
10
|
+
list.map do |map|
|
11
|
+
map.conf :name do |name|
|
12
|
+
name.should_be_present
|
13
|
+
name.should_be_a String
|
14
|
+
name.should_not_be_empty
|
15
|
+
end
|
16
|
+
map.conf :age do |age|
|
17
|
+
age.should_be_a Numeric
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
should "raise ValidationError with nil" do
|
25
|
+
lambda{
|
26
|
+
@spec.process(nil)
|
27
|
+
}.should raise_error(EC::ValidationError, /root needs to be a Array/)
|
28
|
+
end
|
29
|
+
|
30
|
+
should "raise ValidationError with empty string" do
|
31
|
+
lambda{
|
32
|
+
@spec.process('')
|
33
|
+
}.should raise_error(EC::ValidationError, /root needs to be a Array/)
|
34
|
+
end
|
35
|
+
|
36
|
+
should "not raise ValidationError with empty array" do
|
37
|
+
lambda{
|
38
|
+
@spec.process([])
|
39
|
+
}.should_not raise_error(EC::ValidationError)
|
40
|
+
end
|
41
|
+
|
42
|
+
should "not raise ValidationError with valid array" do
|
43
|
+
lambda{
|
44
|
+
@spec.process([
|
45
|
+
{:name => 'simon', :age => 22},
|
46
|
+
{:name => 'anais'}
|
47
|
+
])
|
48
|
+
}.should_not raise_error(EC::ValidationError)
|
49
|
+
end
|
50
|
+
|
51
|
+
should "not raise ValidationError with invalid age" do
|
52
|
+
lambda{
|
53
|
+
@spec.process([
|
54
|
+
{:name => 'simon'},
|
55
|
+
{:name => 'anais', :age => '21'}
|
56
|
+
])
|
57
|
+
}.should raise_error(EC::ValidationError, "root[1].age needs to be a Numeric")
|
58
|
+
end
|
59
|
+
|
60
|
+
should "not raise ValidationError with invalid map" do
|
61
|
+
lambda{
|
62
|
+
@spec.process([
|
63
|
+
{},
|
64
|
+
{:name => 'anais'}
|
65
|
+
])
|
66
|
+
}.should raise_error(EC::ValidationError, "root[0] needs a :name entry")
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class MapSpecificationTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "MapSpecification" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@spec = EC::MapSpecification.new do |map|
|
9
|
+
map.should_be_a Hash
|
10
|
+
map.should_not_be_empty
|
11
|
+
map.conf(:hello) do |hello|
|
12
|
+
hello.should_be_a String
|
13
|
+
hello.should_not_be_empty
|
14
|
+
end
|
15
|
+
map.conf(:bye) do |bye|
|
16
|
+
bye.should_be_present
|
17
|
+
end
|
18
|
+
map.conf(:bye) do |bye|
|
19
|
+
bye.should_be_a String
|
20
|
+
bye.should_not_be_empty
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
should "raise ValidationError with nil" do
|
26
|
+
lambda{
|
27
|
+
@spec.process(nil)
|
28
|
+
}.should raise_error(EC::ValidationError, /root needs to be a Hash/)
|
29
|
+
end
|
30
|
+
|
31
|
+
should "raise ValidationError with empty string" do
|
32
|
+
lambda{
|
33
|
+
@spec.process('')
|
34
|
+
}.should raise_error(EC::ValidationError, /root needs to be a Hash/)
|
35
|
+
end
|
36
|
+
|
37
|
+
should "raise ValidationError with empty hash" do
|
38
|
+
lambda{
|
39
|
+
@spec.process({})
|
40
|
+
}.should raise_error(EC::ValidationError, /root must not be empty./)
|
41
|
+
end
|
42
|
+
|
43
|
+
should "not raise ValidationError with none empty hash" do
|
44
|
+
lambda{
|
45
|
+
@spec.process({ :bye => 'moon' })
|
46
|
+
}.should_not raise_error(EC::ValidationError)
|
47
|
+
end
|
48
|
+
|
49
|
+
should "raise ValidationError with invalid child" do
|
50
|
+
lambda{
|
51
|
+
@spec.process({ :bye => 1 })
|
52
|
+
}.should raise_error(EC::ValidationError, /root.bye needs to be a String/)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class SpecificationTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Specification" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@spec = EC::Specification.new do |value|
|
9
|
+
value.should_be_a String
|
10
|
+
value.should_not_be_empty
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
should "raise ValidationError with nil" do
|
15
|
+
lambda{
|
16
|
+
@spec.process(nil)
|
17
|
+
}.should raise_error(EC::ValidationError, /root needs to be a String/)
|
18
|
+
end
|
19
|
+
|
20
|
+
should "raise ValidationError with empty string" do
|
21
|
+
lambda{
|
22
|
+
@spec.process('')
|
23
|
+
}.should raise_error(EC::ValidationError, /root must not be empty./)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/test/store_test.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class StoreTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context 'Store' do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@path = File.dirname(__FILE__)+'/test.yml'
|
9
|
+
File.open(@path, 'w+') do |f|
|
10
|
+
f.write YAML.dump({'general' => { 'name' => 'ec', 'version' => '0.0.1' }})
|
11
|
+
end
|
12
|
+
|
13
|
+
@path2 = File.dirname(__FILE__)+'/test2.yml'
|
14
|
+
File.open(@path2, 'w+') do |f|
|
15
|
+
f.write YAML.dump({'general' => { 'name' => 'ec2' }})
|
16
|
+
end
|
17
|
+
|
18
|
+
@store = EC::Store.new do |root|
|
19
|
+
root.map(:general) do |general|
|
20
|
+
general.should_be_present
|
21
|
+
general.conf(:name) do |name|
|
22
|
+
name.should_be_present
|
23
|
+
name.should_be_a String
|
24
|
+
name.should_not_be_empty
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
@store.configure_with_yaml(@path)
|
30
|
+
end
|
31
|
+
|
32
|
+
should "be valid" do
|
33
|
+
lambda { @store.validate }.should_not raise_error(EC::ValidationError)
|
34
|
+
end
|
35
|
+
|
36
|
+
should "have correct data" do
|
37
|
+
@store.config[:general][:name].should be('ec')
|
38
|
+
@store.config[:general][:version].should be('0.0.1')
|
39
|
+
end
|
40
|
+
|
41
|
+
should "merge data" do
|
42
|
+
@store.configure_with_yaml(@path2)
|
43
|
+
@store.config[:general][:name].should be('ec2')
|
44
|
+
@store.config[:general][:version].should be('0.0.1')
|
45
|
+
end
|
46
|
+
|
47
|
+
should "reset!" do
|
48
|
+
@store.reset!
|
49
|
+
@store.config.should be({})
|
50
|
+
end
|
51
|
+
|
52
|
+
should "reset!(true)" do
|
53
|
+
@store.reset!(true)
|
54
|
+
@store.config.should be({})
|
55
|
+
@store.specification.should be(nil)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def teardown
|
61
|
+
File.unlink @path if File.exist? @path
|
62
|
+
File.unlink @path2 if File.exist? @path2
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'context'
|
4
|
+
require 'matchy'
|
5
|
+
|
6
|
+
require File.dirname(__FILE__)+'/../lib/ec'
|
7
|
+
|
8
|
+
class Test::Unit::TestCase
|
9
|
+
|
10
|
+
def raise_error(obj = StandardError, msg_re=nil)
|
11
|
+
e = ::EC::RaiseExceptionExpectation.new(obj, self)
|
12
|
+
msg_re = Regexp.new(Regexp.escape(msg_re)) if msg_re.is_a? String
|
13
|
+
e.msg_re = msg_re
|
14
|
+
e
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
module EC
|
20
|
+
class RaiseExceptionExpectation < Matchy::Expectations::Base
|
21
|
+
attr_accessor :msg_re
|
22
|
+
def matches?(receiver)
|
23
|
+
@receiver = receiver
|
24
|
+
begin
|
25
|
+
receiver.call
|
26
|
+
return false
|
27
|
+
rescue StandardError => e
|
28
|
+
@error = e
|
29
|
+
return false unless e.class.ancestors.include?(@expected)
|
30
|
+
return false if @msg_re and e.message !~ @msg_re
|
31
|
+
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def failure_message
|
37
|
+
extra = ""
|
38
|
+
if @error
|
39
|
+
if !@error.class.ancestors.include?(@expected)
|
40
|
+
extra = "but #{@error.class.name} was raised instead"
|
41
|
+
elsif @msg_re
|
42
|
+
extra = "but #{@error.message.inspect} did not match #{@msg_re.inspect}"
|
43
|
+
end
|
44
|
+
else
|
45
|
+
extra = "but none was raised"
|
46
|
+
end
|
47
|
+
|
48
|
+
"Expected #{@receiver.inspect} to raise #{@expected.name}, #{extra}."
|
49
|
+
end
|
50
|
+
|
51
|
+
def negative_failure_message
|
52
|
+
"Expected #{@receiver.inspect} to not raise #{@expected.name}."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/test/update_test.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class UpdateTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "MapSpecification" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@spec = EC::MapSpecification.new do |map|
|
9
|
+
map.should_not_be_empty
|
10
|
+
map.conf(:hello) do |hello|
|
11
|
+
hello.should_be_a String
|
12
|
+
hello.should_not_be_empty
|
13
|
+
end
|
14
|
+
map.conf(:bye) do |bye|
|
15
|
+
bye.should_be_present
|
16
|
+
end
|
17
|
+
map.conf(:bye) do |bye|
|
18
|
+
bye.should_be_a String
|
19
|
+
bye.should_not_be_empty
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
should "update with replace policy" do
|
25
|
+
@spec.update_policy = :replace
|
26
|
+
result = @spec.update({:hello => 'world', :bye => 'moon'}, {:hello => 'sun', :bye => 'earth'})
|
27
|
+
result.should be({:hello => 'sun', :bye => 'earth'})
|
28
|
+
end
|
29
|
+
|
30
|
+
should "update with merge policy" do
|
31
|
+
@spec.update_policy = :merge
|
32
|
+
result = @spec.update({:hello => 'world', :bye => 'moon'}, {:bye => 'earth'})
|
33
|
+
result.should be({:hello => 'world', :bye => 'earth'})
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
context "ListSpecification" do
|
39
|
+
|
40
|
+
setup do
|
41
|
+
@spec = EC::ListSpecification.new do |list|
|
42
|
+
list.should_not_be_empty
|
43
|
+
list.conf do |hello|
|
44
|
+
hello.should_be_a String
|
45
|
+
hello.should_not_be_empty
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
should "update with replace policy" do
|
51
|
+
@spec.update_policy = :replace
|
52
|
+
result = @spec.update(%w( world moon ), %w( sun earth ))
|
53
|
+
result.should be(%w( sun earth ))
|
54
|
+
end
|
55
|
+
|
56
|
+
should "update with merge policy" do
|
57
|
+
@spec.update_policy = :merge
|
58
|
+
result = @spec.update(%w( world moon ), %w( sun earth ))
|
59
|
+
result.should be(%w( world moon sun earth ))
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simonmenke-ec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Simon Menke
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-24 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: simon.menke@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- test/list_specification_test.rb
|
26
|
+
- test/map_specification_test.rb
|
27
|
+
- test/specification_test.rb
|
28
|
+
- test/store_test.rb
|
29
|
+
- test/test_helper.rb
|
30
|
+
- test/update_test.rb
|
31
|
+
- LICENSE.txt
|
32
|
+
- README.textile
|
33
|
+
- lib/ec/list_specification.rb
|
34
|
+
- lib/ec/macros.rb
|
35
|
+
- lib/ec/map_specification.rb
|
36
|
+
- lib/ec/specification.rb
|
37
|
+
- lib/ec/store.rb
|
38
|
+
- lib/ec.rb
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://github.com/simonmenke/ec
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project: ec
|
61
|
+
rubygems_version: 1.2.0
|
62
|
+
signing_key:
|
63
|
+
specification_version: 2
|
64
|
+
summary: EC (EasyConfig) brings verifiable configuration.
|
65
|
+
test_files:
|
66
|
+
- test/list_specification_test.rb
|
67
|
+
- test/map_specification_test.rb
|
68
|
+
- test/specification_test.rb
|
69
|
+
- test/store_test.rb
|
70
|
+
- test/test_helper.rb
|
71
|
+
- test/update_test.rb
|