validhash 0.1.0.a1

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,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Simon Menke
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,15 @@
1
+ = validhash
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
10
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
11
+ * Send me a pull request. Bonus points for topic branches.
12
+
13
+ == Copyright
14
+
15
+ Copyright (c) 2009 Simon Menke. See LICENSE for details.
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "validhash"
8
+ gem.summary = %Q{Configuration Framework}
9
+ gem.description = %Q{Validatable configurations}
10
+ gem.email = "simon@mrhenry.be"
11
+ gem.homepage = "http://github.com/simonmenke/validhash"
12
+ gem.authors = ["Simon Menke"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "validhash #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0.a1
@@ -0,0 +1,67 @@
1
+
2
+ $:.unshift(File.dirname(__FILE__)+'/../lib')
3
+ require 'validhash'
4
+
5
+ class Application < ValidHash
6
+
7
+ def host_file_path
8
+ default { '/etc/hosts' }
9
+ process { File.expand_path(host_file_path) }
10
+ should be_existing_file
11
+ should be_an(String)
12
+ end
13
+
14
+ end
15
+
16
+ module SatelliteOptions
17
+
18
+ def primary_domain
19
+ depends :domains
20
+ default { domains.first }
21
+ should_not be_nil
22
+ should be_an(String)
23
+ end
24
+
25
+ def secondary_domains
26
+ depends :domains
27
+ default { domains[1..-1] }
28
+ should be_an_array_of(String)
29
+ end
30
+
31
+ end
32
+
33
+ class Satellite < Application
34
+ include SatelliteOptions
35
+
36
+ def domains
37
+ process { domains.flatten.compact }
38
+ process { domains.collect { |domain| domain.sub(/^www\./i, '').downcase } }
39
+ process { domains.uniq }
40
+
41
+ should be_present
42
+ should have(:min => 1)
43
+ should be_an_array_of(String)
44
+
45
+ guarantee do
46
+ p [:self, self.primary_domain, self.secondary_domains]
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ app = Satellite.new
53
+ app.domains = %w{ WWW.MRHENRY.BE COOL.com mrhenry.be }
54
+ begin
55
+ app.guarantee!
56
+ rescue ValidHash::InvalidError => e
57
+ puts e.hash.errors
58
+ end
59
+
60
+ puts
61
+
62
+ app = Satellite.new(:host_file_path => '/etc/hosts2')
63
+ begin
64
+ app.guarantee!
65
+ rescue ValidHash::InvalidError => e
66
+ puts e.hash.errors
67
+ end
@@ -0,0 +1,10 @@
1
+
2
+ require 'validhash/validhash'
3
+ require 'validhash/util'
4
+ require 'validhash/definition'
5
+ require 'validhash/errors'
6
+ require 'validhash/option'
7
+ require 'validhash/builder'
8
+ require 'validhash/validations'
9
+ require 'validhash/evaluations'
10
+ require 'validhash/guarantees'
@@ -0,0 +1,40 @@
1
+ class ValidHash
2
+ module Builder
3
+
4
+ def depends(*dependencies)
5
+ @dependencies.concat(dependencies.flatten.compact.collect { |n| n.to_sym }.uniq)
6
+ end
7
+
8
+ def default(&proc)
9
+ @evaluations.push(DefaultEvaluation.new(&proc))
10
+ end
11
+
12
+ def process(&proc)
13
+ @evaluations.push(ProcessEvaluation.new(&proc))
14
+ end
15
+
16
+ def should(validation)
17
+ validation.positive = true
18
+ @validations.push(validation)
19
+ end
20
+ alias_method :__should__, :should
21
+
22
+ def should_not(validation)
23
+ validation.positive = false
24
+ @validations.push(validation)
25
+ end
26
+ alias_method :__should_not__, :should_not
27
+
28
+ def guarantee(guarantee=nil, &proc)
29
+ guarantee ||= BlockGuarantee.new(&proc)
30
+ @guarantees.push(guarantee)
31
+ end
32
+
33
+ def option(m)
34
+ @dependencies, @evaluations, @validations, @guarantees = [], [], [], []
35
+ __send__(m.name)
36
+ Option.new(m.name, @dependencies, @evaluations, @validations, @guarantees)
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,97 @@
1
+ class ValidHash
2
+ class Definition
3
+
4
+ attr_reader :klass
5
+
6
+ def initialize(klass)
7
+ @klass = klass
8
+ end
9
+
10
+ def build!
11
+ return @klass if @original_methods
12
+
13
+ @original_methods = (@klass.instance_methods - ValidHash.instance_methods).collect do |m|
14
+ @klass.instance_method(m)
15
+ end
16
+
17
+ tmp = @klass.new
18
+ tmp.extend Builder
19
+ tmp.extend ValidationHelpers
20
+ @options = @original_methods.inject({}) do |options, m|
21
+ options[m.name.to_sym] = tmp.option(m)
22
+ options
23
+ end
24
+
25
+ @generated_methods = @options.values.inject([]) do |m, option|
26
+ @klass.class_eval(<<-EOC, __FILE__, __LINE__)
27
+ def #{option.name}
28
+ self[:#{option.name}]
29
+ end
30
+ def #{option.name}=(value)
31
+ self[:#{option.name}] = value
32
+ end
33
+ EOC
34
+ m.push("#{option.name}")
35
+ m.push("#{option.name}=")
36
+ m
37
+ end
38
+
39
+ @klass
40
+ end
41
+
42
+ def reset!
43
+ return @klass unless @original_methods
44
+
45
+ @generated_methods.each do |m|
46
+ @klass.send(:remove_method, m)
47
+ end
48
+
49
+ @original_methods.each do |m|
50
+ @klass.send(:define_method, m.name, m)
51
+ end
52
+
53
+ @options = nil
54
+ @original_methods = nil
55
+ @generated_methods = nil
56
+
57
+ @klass
58
+ end
59
+
60
+ def option?(name)
61
+ @options.key?(name.to_sym)
62
+ end
63
+
64
+ def [](name)
65
+ @options[name.to_sym]
66
+ end
67
+
68
+ def each(&proc)
69
+ @options.values.each(&proc)
70
+ end
71
+
72
+ def evaluate(hash, name=nil)
73
+ if name
74
+ self[name].evaluate(hash)
75
+ else
76
+ each { |option| option.evaluate(hash) }
77
+ end
78
+ end
79
+
80
+ def validate(hash, name=nil)
81
+ if name
82
+ self[name].validate(hash)
83
+ else
84
+ each { |option| option.validate(hash) }
85
+ end
86
+ end
87
+
88
+ def guarantee(hash, name=nil)
89
+ if name
90
+ self[name].guarantee(hash)
91
+ else
92
+ each { |option| option.guarantee(hash) }
93
+ end
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,43 @@
1
+ class ValidHash
2
+ class Errors
3
+
4
+ def initialize(hash)
5
+ @hash = hash
6
+ @errors = Hash.new { |h,k| h[k] = [] }
7
+ end
8
+
9
+ def add(on, msg)
10
+ @errors[on.to_sym].push(msg)
11
+ end
12
+
13
+ def empty?
14
+ @errors.values.all? { |msgs| msgs.empty? }
15
+ end
16
+
17
+ def clear
18
+ @errors.clear
19
+ end
20
+
21
+ def on(name)
22
+ @errors[name.to_sym]
23
+ end
24
+
25
+ def each(name=nil)
26
+ names = (name ? [name.to_sym] : @errors.keys.collect{|k|k.to_s}.sort)
27
+ names.each do |name|
28
+ @errors[name.to_sym].each do |msgs|
29
+ msgs.each { |msg| yield(name, msg) }
30
+ end
31
+ end
32
+ end
33
+
34
+ def to_s
35
+ all = ""
36
+ each do |option, msg|
37
+ all.concat "#{option} #{msg}\n"
38
+ end
39
+ all
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ class ValidHash
2
+ class Evaluation
3
+
4
+ def evaluate(hash, name)
5
+ end
6
+
7
+ end
8
+
9
+ class DefaultEvaluation < Evaluation
10
+ def initialize(&proc)
11
+ @proc = proc
12
+ end
13
+
14
+ def evaluate(hash, name)
15
+ unless hash.key?(name)
16
+ proc = ValidHash::Util.bind_proc(@proc, hash)
17
+ hash[name] = proc.call
18
+ end
19
+ end
20
+ end
21
+
22
+ class ProcessEvaluation < Evaluation
23
+ def initialize(&proc)
24
+ @proc = proc
25
+ end
26
+
27
+ def evaluate(hash, name)
28
+ if hash.key?(name)
29
+ proc = ValidHash::Util.bind_proc(@proc, hash)
30
+ hash[name] = proc.call
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ class ValidHash
2
+ class Guarantee
3
+
4
+ def guarantee(hash, name)
5
+ end
6
+
7
+ end
8
+
9
+ class BlockGuarantee < Guarantee
10
+ def initialize(&proc)
11
+ @proc = proc
12
+ end
13
+
14
+ def guarantee(hash, name)
15
+ if hash.key?(name)
16
+ ValidHash::Util.bind_proc(@proc, hash).call
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,48 @@
1
+ class ValidHash
2
+ class Option
3
+
4
+ attr_reader :name
5
+
6
+ def initialize(name, dependencies, evaluations, validations, guarantees)
7
+ @name, @dependencies, @evaluations, @validations, @guarantees = \
8
+ name.to_sym, dependencies, evaluations, validations, guarantees
9
+ end
10
+
11
+ def evaluate(hash)
12
+ keys = hash.instance_variable_get(:@evaluated_keys)
13
+ return if keys.include?(@name)
14
+ keys.push(@name)
15
+
16
+ return unless @dependencies.all? { |name| hash.valid?(name) and hash.key?(name) }
17
+
18
+ @evaluations.each do |evaluation|
19
+ evaluation.evaluate(hash, @name)
20
+ end
21
+ end
22
+
23
+ def validate(hash)
24
+ keys = hash.instance_variable_get(:@validated_keys)
25
+ return if keys.include?(@name)
26
+ keys.push(@name)
27
+
28
+ return unless @dependencies.all? { |name| hash.valid?(name) and hash.key?(name) }
29
+
30
+ @validations.each do |validation|
31
+ validation.validate(hash, @name)
32
+ end
33
+ end
34
+
35
+ def guarantee(hash)
36
+ keys = hash.instance_variable_get(:@guaranteed_keys)
37
+ return if keys.include?(@name)
38
+ keys.push(@name)
39
+
40
+ @dependencies.each { |name| hash.guarantee!(name) }
41
+
42
+ @guarantees.each do |guarantee|
43
+ guarantee.guarantee(hash, @name)
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,14 @@
1
+ class ValidHash
2
+ module Util
3
+
4
+ def self.bind_proc(proc, target)
5
+ m = "__proc_#{rand(1<<20)}"
6
+ mc = (class << target ; self ; end)
7
+ mc.send(:define_method, m, &proc)
8
+ bound_proc = target.method(m)
9
+ mc.send(:remove_method, m)
10
+ bound_proc
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,205 @@
1
+ class ValidHash
2
+ module ValidationHelpers
3
+
4
+ def be_existing_file
5
+ ExistingFileValidation.new
6
+ end
7
+
8
+ def be_existing_directory
9
+ ExistingDirectoryValidation.new
10
+ end
11
+
12
+ def be_present
13
+ PresentValidation.new
14
+ end
15
+
16
+ def be_nil
17
+ NilValidation.new
18
+ end
19
+
20
+ def have(options={})
21
+ SizeValidation.new(options)
22
+ end
23
+
24
+ def empty
25
+ SizeValidation.new(0)
26
+ end
27
+
28
+ def be_a(*types)
29
+ TypeValidation.new(types)
30
+ end
31
+ alias_method :be_an, :be_a
32
+
33
+ def be_an_array_of(*types)
34
+ ArrayTypeValidation.new(types)
35
+ end
36
+
37
+ end
38
+
39
+ class Validation
40
+
41
+ def positive=(value)
42
+ @positive = value
43
+ end
44
+
45
+ def positive?
46
+ !!@positive
47
+ end
48
+
49
+ def validate(hash, name)
50
+ if positive?
51
+ unless positive_match(hash, name, hash[name], hash.key?(name))
52
+ msg = positive_description(hash, name, hash[name], hash.key?(name))
53
+ hash.errors.add(name, "should " + msg) if msg
54
+ end
55
+ else
56
+ unless negative_match(hash, name, hash[name], hash.key?(name))
57
+ msg = negative_description(hash, name, hash[name], hash.key?(name))
58
+ hash.errors.add(name, "should " + msg) if msg
59
+ end
60
+ end
61
+ end
62
+
63
+ def positive_match(hash, name, value, defined)
64
+ true
65
+ end
66
+
67
+ def negative_match(hash, name, value, defined)
68
+ !positive_match(hash, name, value, defined)
69
+ end
70
+
71
+ def positive_description(hash, name, value, defined)
72
+ "be true"
73
+ end
74
+
75
+ def negative_description(hash, name, value, defined)
76
+ "not #{positive_description(hash, name, value, defined)}"
77
+ end
78
+
79
+ end
80
+
81
+ class PresentValidation < Validation
82
+ def positive_match(hash, name, value, defined)
83
+ !!defined
84
+ end
85
+
86
+ def positive_description(hash, name, value, defined)
87
+ "be present"
88
+ end
89
+ end
90
+
91
+ class NilValidation < Validation
92
+ def positive_match(hash, name, value, defined)
93
+ defined and value.nil?
94
+ end
95
+
96
+ def positive_description(hash, name, value, defined)
97
+ return unless defined
98
+
99
+ "be nil"
100
+ end
101
+ end
102
+
103
+ class SizeValidation < Validation
104
+ def initialize(options={})
105
+ options = { :min => options, :max => options } if Numeric === options
106
+ @options = options
107
+ end
108
+
109
+ def positive_match(hash, name, value, defined)
110
+ (defined and
111
+ (value.respond_to?(:size)) and
112
+ (@options.key?(:min) ? (value.size >= @options[:min]) : true) and
113
+ (@options.key?(:max) ? (value.size <= @options[:max]) : true))
114
+ end
115
+
116
+ def positive_description(hash, name, value, defined)
117
+ return unless defined
118
+
119
+ unless value.respond_to?(:size)
120
+ return "respond to :size"
121
+ end
122
+
123
+ if @options.key?(:min) and @options.key?(:max)
124
+ return "have size in range #{@options[:min]}..#{@options[:max]}"
125
+ end
126
+
127
+ if @options.key?(:min)
128
+ return "be min #{@options[:min]} long"
129
+ end
130
+
131
+ if @options.key?(:max)
132
+ return "be max #{@options[:max]} long"
133
+ end
134
+ end
135
+ end
136
+
137
+ class TypeValidation < Validation
138
+ def initialize(types)
139
+ @types = types.flatten.uniq.compact
140
+ end
141
+
142
+ def positive_match(hash, name, value, defined)
143
+ (defined and @types.any? { |t| value.is_a?(t) })
144
+ end
145
+
146
+ def positive_description(hash, name, value, defined)
147
+ return unless defined
148
+
149
+ if @types.size > 1
150
+ "be any of these types: #{@types.join(', ')}"
151
+ else
152
+ "be a #{@types.first}"
153
+ end
154
+ end
155
+ end
156
+
157
+ class ArrayTypeValidation < TypeValidation
158
+ def initialize(types)
159
+ super([Array])
160
+ @subtypes = types.flatten.uniq.compact
161
+ end
162
+
163
+ def positive_match(hash, name, value, defined)
164
+ (super(hash, name, value, defined) and value.all? { |v| @subtypes.any? { |t| v.is_a?(t) }})
165
+ end
166
+
167
+ def positive_description(hash, name, value, defined)
168
+ return unless defined
169
+
170
+ unless value.is_a?(Array)
171
+ "be an Array"
172
+ end
173
+
174
+ if @subtypes.size > 1
175
+ "be an array of any of these types: #{@subtypes.join(', ')}"
176
+ else
177
+ "be an array of #{@subtypes.first}"
178
+ end
179
+ end
180
+ end
181
+
182
+ class ExistingFileValidation < Validation
183
+ def positive_match(hash, name, value, defined)
184
+ defined and File.file?(value)
185
+ end
186
+
187
+ def positive_description(hash, name, value, defined)
188
+ return unless defined
189
+
190
+ "be an existing file"
191
+ end
192
+ end
193
+
194
+ class ExistingDirectoryValidation < Validation
195
+ def positive_match(hash, name, value, defined)
196
+ defined and File.directory?(value)
197
+ end
198
+
199
+ def positive_description(hash, name, value, defined)
200
+ return unless defined
201
+
202
+ "be an existing directory"
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,111 @@
1
+ class ValidHash < Hash
2
+
3
+ class InvalidError < RuntimeError
4
+ attr_reader :hash
5
+ def initialize(hash)
6
+ @hash = hash
7
+ super("invalid hash")
8
+ end
9
+ end
10
+
11
+ class << self
12
+ def definition
13
+ @definition ||= ValidHash::Definition.new(self)
14
+ end
15
+ end
16
+
17
+ def initialize(other={})
18
+ self.class.definition.build!
19
+
20
+ super()
21
+ @evaluated_keys = []
22
+ @validated_keys = []
23
+ @guaranteed_keys = []
24
+ @evaluating_keys = []
25
+
26
+ other.each { |k,v| self[k] = v }
27
+ end
28
+
29
+ def errors
30
+ @errors ||= Errors.new(self)
31
+ end
32
+
33
+ def option?(name)
34
+ self.class.definition.option?(name)
35
+ end
36
+
37
+ def key?(name)
38
+ raise "No option called #{name.to_s.inspect}" unless option?(name)
39
+ super(name.to_sym)
40
+ end
41
+
42
+ def [](name)
43
+ raise "No option called #{name.to_s.inspect}" unless option?(name)
44
+ name = name.to_sym
45
+ unless @evaluating_keys.include?(name)
46
+ @evaluating_keys.push(name)
47
+ self.class.definition[name].evaluate(self)
48
+ @evaluating_keys.delete(name)
49
+ end
50
+ super(name)
51
+ end
52
+
53
+ def []=(name, value)
54
+ raise "No option called #{name.to_s.inspect}" unless option?(name)
55
+ unless @evaluating_keys.include?(name)
56
+ @evaluated_keys.delete(name.to_sym)
57
+ @validated_keys.delete(name.to_sym)
58
+ @guaranteed_keys.delete(name.to_sym)
59
+ end
60
+ super(name.to_sym, value)
61
+ end
62
+
63
+ def delete(name)
64
+ raise "No option called #{name.to_s.inspect}" unless option?(name)
65
+ unless @evaluating_keys.include?(name)
66
+ @evaluated_keys.delete(name.to_sym)
67
+ @validated_keys.delete(name.to_sym)
68
+ @guaranteed_keys.delete(name.to_sym)
69
+ end
70
+ super(name.to_sym)
71
+ end
72
+
73
+ def evaluate!(name=nil)
74
+ self.class.definition.evaluate(self, name)
75
+ end
76
+
77
+ def validate!(name=nil)
78
+ evaluate!(name)
79
+ self.class.definition.validate(self, name)
80
+ end
81
+
82
+ def guarantee!(name=nil)
83
+ if valid!
84
+ self.class.definition.guarantee(self, name)
85
+ return true
86
+ end
87
+ end
88
+
89
+ def valid?(name=nil)
90
+ if name
91
+ self.errors.on(name).clear
92
+ @validated_keys = []
93
+ validate!(name)
94
+ self.errors.on(name).empty?
95
+ else
96
+ self.errors.clear
97
+ @validated_keys = []
98
+ validate!
99
+ self.errors.empty?
100
+ end
101
+ end
102
+
103
+ def valid!(name=nil)
104
+ if valid?(name)
105
+ return true
106
+ else
107
+ raise InvalidError, self
108
+ end
109
+ end
110
+
111
+ end
@@ -0,0 +1,2 @@
1
+ --color
2
+ -f specdoc
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'validhash'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
@@ -0,0 +1,70 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe ValidHash do
4
+
5
+ it "is a Hash" do
6
+ ValidHash.superclass.should == Hash
7
+ end
8
+
9
+ it "can define blank options" do
10
+ c = Class.new(ValidHash) do
11
+ def hello
12
+ end
13
+ end.new
14
+
15
+ c.option?(:hello).should == true
16
+ c.should respond_to(:hello)
17
+ c.should respond_to(:hello=)
18
+ end
19
+
20
+ it "can validate the value of an option" do
21
+ c = Class.new(ValidHash) do
22
+ def hello
23
+ __should__ be_nil
24
+ end
25
+ end.new
26
+
27
+ c.hello = nil
28
+ c.should be_valid(:hello)
29
+
30
+ c.hello = 'hello'
31
+ c.should_not be_valid(:hello)
32
+ end
33
+
34
+ it "can validate the values of all options" do
35
+ c = Class.new(ValidHash) do
36
+ def hello
37
+ __should__ be_nil
38
+ end
39
+ end.new
40
+
41
+ c.hello = nil
42
+ c.should be_valid
43
+
44
+ c.hello = 'hello'
45
+ c.should_not be_valid
46
+ end
47
+
48
+ it "can process the value of an option" do
49
+ c = Class.new(ValidHash) do
50
+ def hello
51
+ process { hello.to_s }
52
+ end
53
+ end.new
54
+
55
+ c.hello.should be_nil
56
+ c.hello = 1
57
+ c.hello.should == '1'
58
+ end
59
+
60
+ it "can assign a default value to an option" do
61
+ c = Class.new(ValidHash) do
62
+ def hello
63
+ default { 'Anais' }
64
+ end
65
+ end.new
66
+
67
+ c.hello.should == 'Anais'
68
+ end
69
+
70
+ end
@@ -0,0 +1,66 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{validhash}
8
+ s.version = "0.1.0.a1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Simon Menke"]
12
+ s.date = %q{2009-10-26}
13
+ s.description = %q{Validatable configurations}
14
+ s.email = %q{simon@mrhenry.be}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "examples/001.rb",
27
+ "lib/validhash.rb",
28
+ "lib/validhash/builder.rb",
29
+ "lib/validhash/definition.rb",
30
+ "lib/validhash/errors.rb",
31
+ "lib/validhash/evaluations.rb",
32
+ "lib/validhash/guarantees.rb",
33
+ "lib/validhash/option.rb",
34
+ "lib/validhash/util.rb",
35
+ "lib/validhash/validations.rb",
36
+ "lib/validhash/validhash.rb",
37
+ "spec/spec.opts",
38
+ "spec/spec_helper.rb",
39
+ "spec/validhash_spec.rb",
40
+ "validhash.gemspec"
41
+ ]
42
+ s.homepage = %q{http://github.com/simonmenke/validhash}
43
+ s.rdoc_options = ["--charset=UTF-8"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.3.5}
46
+ s.summary = %q{Configuration Framework}
47
+ s.test_files = [
48
+ "spec/spec_helper.rb",
49
+ "spec/validhash_spec.rb",
50
+ "examples/001.rb"
51
+ ]
52
+
53
+ if s.respond_to? :specification_version then
54
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
+ s.specification_version = 3
56
+
57
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
58
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
59
+ else
60
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
61
+ end
62
+ else
63
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
64
+ end
65
+ end
66
+
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: validhash
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.a1
5
+ platform: ruby
6
+ authors:
7
+ - Simon Menke
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-26 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9
24
+ version:
25
+ description: Validatable configurations
26
+ email: simon@mrhenry.be
27
+ engine_dependencies: {}
28
+
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files:
34
+ - LICENSE
35
+ - README.rdoc
36
+ files:
37
+ - .document
38
+ - .gitignore
39
+ - LICENSE
40
+ - README.rdoc
41
+ - Rakefile
42
+ - VERSION
43
+ - examples/001.rb
44
+ - lib/validhash.rb
45
+ - lib/validhash/builder.rb
46
+ - lib/validhash/definition.rb
47
+ - lib/validhash/errors.rb
48
+ - lib/validhash/evaluations.rb
49
+ - lib/validhash/guarantees.rb
50
+ - lib/validhash/option.rb
51
+ - lib/validhash/util.rb
52
+ - lib/validhash/validations.rb
53
+ - lib/validhash/validhash.rb
54
+ - spec/spec.opts
55
+ - spec/spec_helper.rb
56
+ - spec/validhash_spec.rb
57
+ - validhash.gemspec
58
+ has_rdoc: true
59
+ homepage: http://github.com/simonmenke/validhash
60
+ licenses: []
61
+
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --charset=UTF-8
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">"
76
+ - !ruby/object:Gem::Version
77
+ version: 1.3.1
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.3.5
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Configuration Framework
86
+ test_files:
87
+ - spec/spec_helper.rb
88
+ - spec/validhash_spec.rb
89
+ - examples/001.rb