simonmenke-ec 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|