fact_checker 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/README +23 -0
- data/Rakefile +13 -0
- data/examples/README.md +72 -0
- data/examples/basic.rb +60 -0
- data/fact_checker.gemspec +29 -0
- data/lib/fact_checker/base.rb +78 -0
- data/lib/fact_checker/version.rb +5 -0
- data/lib/fact_checker.rb +31 -0
- data/spec/fact_checker/base_spec.rb +180 -0
- data/spec/fact_checker/version_spec.rb +7 -0
- data/spec/fact_checker_inheritance_spec.rb +63 -0
- data/spec/fact_checker_spec.rb +74 -0
- data/spec/spec.rake +17 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/classes_with_facts.rb +27 -0
- data/spec/support/shared_facts_behaviour.rb +17 -0
- metadata +100 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2@fact_checker 2>/dev/null
|
data/Gemfile
ADDED
data/README
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
1. What is FactChecker
|
2
|
+
|
3
|
+
Simple ruby gem to check hierarchically dependent "facts" about objects.
|
4
|
+
|
5
|
+
2. Getting started
|
6
|
+
|
7
|
+
2.1 Installation
|
8
|
+
|
9
|
+
gem install fact_checker
|
10
|
+
|
11
|
+
2.2 Usage
|
12
|
+
|
13
|
+
https://github.com/alexis/fact_checker/tree/master/examples
|
14
|
+
|
15
|
+
3. Development / Contributing
|
16
|
+
|
17
|
+
3.1 Testing code with rspec
|
18
|
+
|
19
|
+
rake spec
|
20
|
+
|
21
|
+
3.2 Testing code coverage with rcov for ruby 1.8
|
22
|
+
|
23
|
+
rcov -Ilib:spec --exclude gem spec/fact_checker_spec.rb
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
require 'bundler'
|
5
|
+
|
6
|
+
Bundler::GemHelper.install_tasks
|
7
|
+
|
8
|
+
Dir['lib/tasks/**/*.rake'].
|
9
|
+
concat(Dir['tasks/**/*.rake']).
|
10
|
+
concat(Dir['{test,spec}/*.rake']).each { |rake| load(rake) }
|
11
|
+
|
12
|
+
task :default => :spec
|
13
|
+
task :test => :spec # for http://test.rubygems.org/
|
data/examples/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# FactChecker / Examples
|
2
|
+
|
3
|
+
## How to run
|
4
|
+
|
5
|
+
``` ruby
|
6
|
+
bundle exec ruby -rubygems examples/basic.rb
|
7
|
+
```
|
8
|
+
|
9
|
+
## BasicExample
|
10
|
+
|
11
|
+
``` ruby
|
12
|
+
# encoding: utf-8
|
13
|
+
|
14
|
+
require 'fact_checker'
|
15
|
+
|
16
|
+
class BasicExample
|
17
|
+
include FactChecker
|
18
|
+
|
19
|
+
def_fact :be
|
20
|
+
def_fact :be_or => :be
|
21
|
+
def_fact :be_or_not => :be, :if => :my_requirement?
|
22
|
+
def_fact :be_or_not_to => [:be, :be_or_not], :if => :my_requirement?
|
23
|
+
def_fact :be_or_not_to_be => :be, :if => lambda { |context| !context.my_requirement? }
|
24
|
+
end
|
25
|
+
|
26
|
+
target = BasicExample.new
|
27
|
+
|
28
|
+
def target.my_requirement?; false end
|
29
|
+
|
30
|
+
p target.fact_possible? :be
|
31
|
+
# => true
|
32
|
+
p target.fact_accomplished? :be
|
33
|
+
# => true
|
34
|
+
p target.be?
|
35
|
+
# => true
|
36
|
+
|
37
|
+
puts
|
38
|
+
|
39
|
+
p target.fact_possible? :be_or
|
40
|
+
# => true
|
41
|
+
p target.fact_accomplished? :be_or
|
42
|
+
# => true
|
43
|
+
p target.be_or?
|
44
|
+
# => true
|
45
|
+
|
46
|
+
puts
|
47
|
+
|
48
|
+
p target.fact_possible? :be_or_not
|
49
|
+
# => true
|
50
|
+
p target.fact_accomplished? :be_or_not
|
51
|
+
# => false
|
52
|
+
p target.be_or_not?
|
53
|
+
# => false
|
54
|
+
|
55
|
+
puts
|
56
|
+
|
57
|
+
p target.fact_possible? :be_or_not_to
|
58
|
+
# => false
|
59
|
+
p target.fact_accomplished? :be_or_not_to
|
60
|
+
# => false
|
61
|
+
p target.be_or_not_to?
|
62
|
+
# => false
|
63
|
+
|
64
|
+
puts
|
65
|
+
|
66
|
+
p target.fact_possible? :be_or_not_to_be
|
67
|
+
# => true
|
68
|
+
p target.fact_accomplished? :be_or_not_to_be
|
69
|
+
# => true
|
70
|
+
p target.be_or_not_to_be?
|
71
|
+
# => true
|
72
|
+
```
|
data/examples/basic.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'fact_checker'
|
4
|
+
|
5
|
+
class BasicExample
|
6
|
+
include FactChecker
|
7
|
+
|
8
|
+
def_fact :be
|
9
|
+
def_fact :be_or => :be
|
10
|
+
def_fact :be_or_not => :be, :if => :my_requirement?
|
11
|
+
def_fact :be_or_not_to => [:be, :be_or_not], :if => :my_requirement?
|
12
|
+
def_fact :be_or_not_to_be => :be, :if => lambda { |context| !context.my_requirement? }
|
13
|
+
end
|
14
|
+
|
15
|
+
target = BasicExample.new
|
16
|
+
|
17
|
+
def target.my_requirement?; false end
|
18
|
+
|
19
|
+
p target.fact_possible? :be
|
20
|
+
# => true
|
21
|
+
p target.fact_accomplished? :be
|
22
|
+
# => true
|
23
|
+
p target.be?
|
24
|
+
# => true
|
25
|
+
|
26
|
+
puts
|
27
|
+
|
28
|
+
p target.fact_possible? :be_or
|
29
|
+
# => true
|
30
|
+
p target.fact_accomplished? :be_or
|
31
|
+
# => true
|
32
|
+
p target.be_or?
|
33
|
+
# => true
|
34
|
+
|
35
|
+
puts
|
36
|
+
|
37
|
+
p target.fact_possible? :be_or_not
|
38
|
+
# => true
|
39
|
+
p target.fact_accomplished? :be_or_not
|
40
|
+
# => false
|
41
|
+
p target.be_or_not?
|
42
|
+
# => false
|
43
|
+
|
44
|
+
puts
|
45
|
+
|
46
|
+
p target.fact_possible? :be_or_not_to
|
47
|
+
# => false
|
48
|
+
p target.fact_accomplished? :be_or_not_to
|
49
|
+
# => false
|
50
|
+
p target.be_or_not_to?
|
51
|
+
# => false
|
52
|
+
|
53
|
+
puts
|
54
|
+
|
55
|
+
p target.fact_possible? :be_or_not_to_be
|
56
|
+
# => true
|
57
|
+
p target.fact_accomplished? :be_or_not_to_be
|
58
|
+
# => true
|
59
|
+
p target.be_or_not_to_be?
|
60
|
+
# => true
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$:.push File.expand_path("../lib", __FILE__)
|
4
|
+
require "fact_checker/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "fact_checker"
|
8
|
+
s.version = FactChecker::VERSION
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.authors = ["Alexey Smolianinov", "Ivan Povalyukhin"]
|
11
|
+
s.email = ["alexisowl+fact_checker@gmail.com"]
|
12
|
+
s.homepage = "https://github.com/alexis/fact_checker"
|
13
|
+
s.summary = %q{Checks facts which may depend on other facts}
|
14
|
+
s.description = %q{Simple gem to check hierarchically dependent "facts" about objects}
|
15
|
+
|
16
|
+
s.rubyforge_project = "fact_checker"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.required_ruby_version = ">= 1.8.7"
|
24
|
+
s.required_rubygems_version = ">= 1.3.5"
|
25
|
+
|
26
|
+
s.add_development_dependency 'rspec', '~> 2.6'
|
27
|
+
s.add_development_dependency 'rake'
|
28
|
+
s.add_development_dependency 'bundler'
|
29
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FactChecker
|
4
|
+
class Base
|
5
|
+
attr_accessor :facts, :dependencies, :requirements
|
6
|
+
|
7
|
+
def initialize(facts = nil, deps = nil, reqs = nil)
|
8
|
+
@facts = facts || []
|
9
|
+
@dependencies = deps || {}
|
10
|
+
@requirements = reqs || {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize_copy(orig)
|
14
|
+
super
|
15
|
+
@facts = orig.facts.dup
|
16
|
+
@dependencies = orig.dependencies.dup
|
17
|
+
@requirements = orig.requirements.dup
|
18
|
+
end
|
19
|
+
|
20
|
+
def accomplished_facts(context)
|
21
|
+
facts.select{ |fact| fact_accomplished?(context, fact) }
|
22
|
+
end
|
23
|
+
def possible_facts(context)
|
24
|
+
facts.select{ |fact| fact_possible?(context, fact) }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Checks if requirement and dependency for the fact are satisfied
|
28
|
+
def fact_accomplished?(context, fact)
|
29
|
+
fact_possible?(context, fact) && requirement_satisfied_for?(context, fact)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Checks if dependency for the fact is satisfied
|
33
|
+
def fact_possible?(context, fact)
|
34
|
+
[* @dependencies[fact] || []].all?{ |dep| fact_accomplished?(context, dep) }
|
35
|
+
end
|
36
|
+
|
37
|
+
# Checks if requirement for the fact is satisfied (no dependency checks here)
|
38
|
+
def requirement_satisfied_for?(context, fact)
|
39
|
+
return false unless @facts.include?(fact)
|
40
|
+
|
41
|
+
case req = @requirements[fact]
|
42
|
+
when Symbol then context.send(req)
|
43
|
+
when Proc then req.arity < 1 ? req.call : req.call(context)
|
44
|
+
when NilClass then true
|
45
|
+
else raise RuntimeError, "can't check this fact - wrong requirement"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Syntactic sugar, adds fact with its requirement and dependency. Examples:
|
50
|
+
# - def_fact(:fact)
|
51
|
+
# - def_fact(:fact, :if => :requirement)
|
52
|
+
# - def_fact(:fact => :dependency)
|
53
|
+
# - def_fact(:fact => :dependency, :if => :requirement)
|
54
|
+
def def_fact(*opt)
|
55
|
+
raise ArgumentError, "wrong number of arguments (#{opt.size} for 2)" if opt.size > 2
|
56
|
+
raise ArgumentError, "wrong number of arguments (0 for 1)" if opt.size == 0
|
57
|
+
|
58
|
+
if opt[0].is_a?(Hash)
|
59
|
+
raise ArgumentError, "wrong arguments (hash argument can only be the last one)" if opt.size > 1
|
60
|
+
hash = opt[0]
|
61
|
+
else
|
62
|
+
raise ArgumentError, "wrong arguments (second argument must be a hash)" if opt[1] && ! opt[1].is_a?(Hash)
|
63
|
+
hash = (opt[1] || {}).merge(opt[0] => nil)
|
64
|
+
end
|
65
|
+
|
66
|
+
req = hash.delete(:if)
|
67
|
+
fact = hash.keys.first
|
68
|
+
dep = hash.delete(fact)
|
69
|
+
|
70
|
+
raise ArgumentError, "wrong arguments: #{hash.keys.join(', ')}" if hash.size > 0
|
71
|
+
|
72
|
+
@requirements[fact] = req
|
73
|
+
@dependencies[fact] = dep
|
74
|
+
@facts |= [fact]
|
75
|
+
fact
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/fact_checker.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "fact_checker/base"
|
4
|
+
require "fact_checker/version"
|
5
|
+
|
6
|
+
module FactChecker
|
7
|
+
def self.included(klass)
|
8
|
+
klass.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def inherited(child)
|
13
|
+
child.instance_variable_set('@fact_checker', fact_checker.dup)
|
14
|
+
end
|
15
|
+
|
16
|
+
def def_fact(*opts)
|
17
|
+
fact_name = fact_checker.def_fact(*opts)
|
18
|
+
define_method(fact_name.to_s << '?') { fact_accomplished?(fact_name) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def fact_checker
|
22
|
+
@fact_checker ||= FactChecker::Base.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Delegate methods to self.class.fact_checker
|
27
|
+
[:fact_accomplished?, :fact_possible?, :accomplished_facts, :possible_facts].each do |name|
|
28
|
+
define_method(name) { |*opts| self.class.fact_checker.send(name, self, *opts) }
|
29
|
+
end
|
30
|
+
def facts; self.class.fact_checker.facts; end
|
31
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe FactChecker::Base do
|
6
|
+
describe "constructor" do
|
7
|
+
it "should accept facts, dependencies and requirements as arguments" do
|
8
|
+
fc = FactChecker::Base.new([:a, :b], {:a => :b}, {:b => :nil?})
|
9
|
+
fc.facts.should == [:a, :b]
|
10
|
+
fc.dependencies.should == {:a => :b}
|
11
|
+
fc.requirements.should == {:b => :nil?}
|
12
|
+
end
|
13
|
+
it "should use empty hash as a default for requirements" do
|
14
|
+
fc = FactChecker::Base.new([:a, :b], {:a => :b})
|
15
|
+
fc.requirements.should == {}
|
16
|
+
end
|
17
|
+
it "should use empty hash as a default for dependencies" do
|
18
|
+
fc = FactChecker::Base.new([:a, :b])
|
19
|
+
fc.dependencies.should == {}
|
20
|
+
end
|
21
|
+
it "should use empty array as a default for facts" do
|
22
|
+
fc = FactChecker::Base.new()
|
23
|
+
fc.facts.should == []
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#facts" do
|
28
|
+
it "should return all facts" do
|
29
|
+
fc = FactChecker::Base.new([:f1, :f2])
|
30
|
+
fc.facts.should == [:f1, :f2]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#accomplished_facts" do
|
35
|
+
it "should return accomplished facts" do
|
36
|
+
fc = FactChecker::Base.new([:f1, :f2], nil, {:f2 => lambda{ false }})
|
37
|
+
fc.accomplished_facts("context").should == [:f1]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#possible_facts" do
|
42
|
+
it "should return possible facts" do
|
43
|
+
fc = FactChecker::Base.new([:f1, :f2], {:f1 => :f2}, {:f2 => lambda{ false }})
|
44
|
+
fc.possible_facts("context").should == [:f2]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#requirement_satisfied_for?" do
|
49
|
+
it "should return true if no requerment defined for the step" do
|
50
|
+
fc = FactChecker::Base.new([:f1])
|
51
|
+
fc.requirement_satisfied_for?(1, :f1).should be_true
|
52
|
+
end
|
53
|
+
it "should return false if fact is unknown" do
|
54
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => :nil?})
|
55
|
+
fc.requirement_satisfied_for?(1, :f2).should be_false
|
56
|
+
end
|
57
|
+
it "should return false if requirement is :symbol and context.symbol() == false" do
|
58
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => :nil?})
|
59
|
+
fc.requirement_satisfied_for?(1, :f1).should be_false
|
60
|
+
end
|
61
|
+
it "should return true if requirement is :symbol and context.symbol() == true" do
|
62
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => :nil?})
|
63
|
+
fc.requirement_satisfied_for?(nil, :f1).should be_true
|
64
|
+
end
|
65
|
+
it "should return false if requirement is Proc and proc(context) == false" do
|
66
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => lambda{|t| t.nil?}})
|
67
|
+
fc.requirement_satisfied_for?(1, :f1).should be_false
|
68
|
+
end
|
69
|
+
it "should return true if requirement is Proc and proc(context) == true" do
|
70
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => lambda{|t| t.nil?}})
|
71
|
+
fc.requirement_satisfied_for?(nil, :f1).should be_true
|
72
|
+
end
|
73
|
+
it "should return false if requirement is Proc with arity < 1 and proc() == false" do
|
74
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => lambda{false}})
|
75
|
+
fc.requirement_satisfied_for?(nil, :f1).should be_false
|
76
|
+
end
|
77
|
+
it "should return true if requirement is Proc with arity < 1 and proc() == true" do
|
78
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => lambda{true}})
|
79
|
+
fc.requirement_satisfied_for?(nil, :f1).should be_true
|
80
|
+
end
|
81
|
+
it "should raise RuntimeError if requirement has wrong type" do
|
82
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => "wrong"})
|
83
|
+
lambda{fc.requirement_satisfied_for?(nil, :f1)}.should raise_error(RuntimeError)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#fact_accomplished?" do
|
88
|
+
it "should return false if fact is unknown" do
|
89
|
+
fc = FactChecker::Base.new([:f2], nil, {:f1 => :nil?})
|
90
|
+
fc.fact_accomplished?(nil, :f1).should be_false
|
91
|
+
end
|
92
|
+
it "should return true if requirement satisfied and fact has no dependencies" do
|
93
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => lambda{|o| o.size > 2}})
|
94
|
+
fc.fact_accomplished?("name", :f1).should be_true
|
95
|
+
end
|
96
|
+
it "should return false if requirement not satisfied (fact has no dependencies)" do
|
97
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => :nil?})
|
98
|
+
fc.fact_accomplished?("something", :f1).should be_false
|
99
|
+
end
|
100
|
+
it "should return false if fact has unsatisfied dependencies" do
|
101
|
+
fc = FactChecker::Base.new([:f1, :f2], {:f1 => :f2}, {:f2 => :nil?})
|
102
|
+
fc.fact_accomplished?("something", :f1).should be_false
|
103
|
+
end
|
104
|
+
it "should return false if fact has both satisfied and unsatisfied dependencies" do
|
105
|
+
fc = FactChecker::Base.new([:f1, :f2, :f3, :f4], {:f1 => [:f2, :f3], :f3 => :f4}, {:f2 => :size, :f3 => :size, :f4 => :nil?})
|
106
|
+
fc.fact_accomplished?("something", :f1).should be_false
|
107
|
+
end
|
108
|
+
it "should return true if all dependencies are satisfied and fact has no requirements" do
|
109
|
+
fc = FactChecker::Base.new([:f1, :f2, :f3, :f4], {:f1 => [:f2, :f3], :f3 => :f4}, {:f2 => :size, :f3 => :size, :f4 => :size})
|
110
|
+
fc.fact_accomplished?("something", :f1).should be_true
|
111
|
+
end
|
112
|
+
it "should return false if requirements not satisfied (all dependencies are satisfied)" do
|
113
|
+
fc = FactChecker::Base.new([:f1, :f2, :f3, :f4], {:f1 => [:f2, :f3], :f3 => :f4}, {:f1 => :nil?, :f2 => :size, :f3 => :size, :f4 => :size})
|
114
|
+
fc.fact_accomplished?("something", :f1).should be_false
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#fact_possible?" do
|
119
|
+
it "should return true if fact is unknown" do
|
120
|
+
fc = FactChecker::Base.new([:f2], nil, {:f1 => :nil?})
|
121
|
+
fc.fact_possible?(nil, :f1).should be_true
|
122
|
+
end
|
123
|
+
it "should return true if dependencies satisfied (even if requirement is not satisfied)" do
|
124
|
+
fc = FactChecker::Base.new([:f1], nil, {:f1 => :nil?})
|
125
|
+
fc.fact_possible?(1, :f1).should be_true
|
126
|
+
end
|
127
|
+
it "should return false if dependencies unsatisfied (even if requirement is satisfied)" do
|
128
|
+
fc = FactChecker::Base.new([:f1], {:f1 => :f2}, {:f2 => :nil?})
|
129
|
+
fc.fact_possible?(1, :f1).should be_false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "#def_fact" do
|
134
|
+
let(:fc) { FactChecker::Base.new }
|
135
|
+
|
136
|
+
it "should add argument to facts when called with (:fact) and return (:fact)" do
|
137
|
+
fc.def_fact(:f1).should be :f1
|
138
|
+
fc.def_fact(:f2).should be :f2
|
139
|
+
fc.facts.should == [:f1, :f2]
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should define fact correctly when called with (:fact, :if => :requirement)" do
|
143
|
+
fc.def_fact(:f1)
|
144
|
+
fc.def_fact(:f2, :if => :nil?)
|
145
|
+
fc.facts.should == [:f1, :f2]
|
146
|
+
fc.requirements[:f2].should == :nil?
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should define fact correctly when called with (:fact => :dependency)" do
|
150
|
+
fc.def_fact(:f1)
|
151
|
+
fc.def_fact(:f2 => :f1)
|
152
|
+
fc.facts.should == [:f1, :f2]
|
153
|
+
fc.dependencies[:f2].should == :f1
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should define fact correctly when called with (:fact => :dependency, :if => :requirement)" do
|
157
|
+
fc.def_fact(:f1)
|
158
|
+
fc.def_fact(:f2 => :f1, :if => :nil?)
|
159
|
+
fc.facts.should == [:f1, :f2]
|
160
|
+
fc.dependencies[:f2].should == :f1
|
161
|
+
fc.requirements[:f2].should == :nil?
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should redefine fact if a fact with a given name already exists" do
|
165
|
+
fc.def_fact(:f1 => :f2, :if => :nil?)
|
166
|
+
fc.def_fact(:f1)
|
167
|
+
fc.facts.should == [:f1]
|
168
|
+
fc.requirements[:f1].should be_nil
|
169
|
+
fc.dependencies[:f1].should be_nil
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should raise ArgumentError exception when called with wrong arguments" do
|
173
|
+
expect { fc.def_fact() }.to raise_error ArgumentError
|
174
|
+
expect { fc.def_fact(:f1, {:if => :nil?}, true) }.to raise_error ArgumentError
|
175
|
+
expect { fc.def_fact(:f1, :f2) }.to raise_error ArgumentError
|
176
|
+
expect { fc.def_fact({:if => :nil?}, :f1) }.to raise_error ArgumentError
|
177
|
+
expect { fc.def_fact(:f1 => :f2, :if => :nil?, :something_else => true) }.to raise_error ArgumentError
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'FactCheckerInheritance' do
|
6
|
+
describe ChildOfClassWithFacts do
|
7
|
+
subject { ChildOfClassWithFacts }
|
8
|
+
|
9
|
+
it { should respond_to :def_fact }
|
10
|
+
its(:fact_checker) { should be_kind_of FactChecker::Base }
|
11
|
+
|
12
|
+
describe 'context for inherited facts' do
|
13
|
+
let(:target) { ChildOfClassWithFacts.new }
|
14
|
+
|
15
|
+
context 'inherited bare fact', :fact => :bare_fact do
|
16
|
+
it_behaves_like 'an accomplished fact', true
|
17
|
+
it_behaves_like 'a possible fact', true
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'inherited true fact with no dependencies', :fact => :true_fact_with_no_dependencies do
|
21
|
+
it_behaves_like 'an accomplished fact', true
|
22
|
+
it_behaves_like 'a possible fact', true
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'inherited true fact with true dependencies', :fact => :true_fact_with_true_dependencies do
|
26
|
+
it_behaves_like 'an accomplished fact', true
|
27
|
+
it_behaves_like 'a possible fact', true
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'inherited true fact with false dependencies', :fact => :true_fact_with_false_dependencies do
|
31
|
+
it_behaves_like 'an accomplished fact', false
|
32
|
+
it_behaves_like 'a possible fact', false
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'inherited false fact with no dependencies', :fact => :false_fact_with_no_dependencies do
|
36
|
+
it_behaves_like 'an accomplished fact', false
|
37
|
+
it_behaves_like 'a possible fact', true
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'inherited false fact with true dependencies', :fact => :false_fact_with_true_dependencies do
|
41
|
+
it_behaves_like 'an accomplished fact', false
|
42
|
+
it_behaves_like 'a possible fact', true
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'inherited false fact with false dependencies', :fact => :false_fact_with_false_dependencies do
|
46
|
+
it_behaves_like 'an accomplished fact', false
|
47
|
+
it_behaves_like 'a possible fact', false
|
48
|
+
end
|
49
|
+
|
50
|
+
specify '#facts' do
|
51
|
+
target.facts.size.should == 7
|
52
|
+
end
|
53
|
+
|
54
|
+
specify '#accomplished_facts' do
|
55
|
+
target.accomplished_facts.should == [ :bare_fact, :true_fact_with_no_dependencies, :true_fact_with_true_dependencies ]
|
56
|
+
end
|
57
|
+
|
58
|
+
specify '#possible_facts' do
|
59
|
+
target.possible_facts.should == target.facts - [ :true_fact_with_false_dependencies, :false_fact_with_false_dependencies ]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'FactChecker' do
|
6
|
+
describe ClassWithNoFacts do
|
7
|
+
its(:facts) { should == [] }
|
8
|
+
its(:possible_facts) { should == [] }
|
9
|
+
its(:accomplished_facts) { should == [] }
|
10
|
+
|
11
|
+
specify '#fact_possible? and #fact_accomplished?' do
|
12
|
+
subject.fact_possible?(:unknown_fact).should be_true
|
13
|
+
subject.fact_accomplished?(:unknown_fact).should be_false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe ClassWithFacts do
|
18
|
+
subject { ClassWithFacts }
|
19
|
+
|
20
|
+
it { should respond_to :def_fact }
|
21
|
+
its(:fact_checker) { should be_kind_of FactChecker::Base }
|
22
|
+
|
23
|
+
describe 'context for facts' do
|
24
|
+
let(:target) { ClassWithFacts.new }
|
25
|
+
|
26
|
+
context 'given bare fact', :fact => :bare_fact do
|
27
|
+
it_behaves_like 'an accomplished fact', true
|
28
|
+
it_behaves_like 'a possible fact', true
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'given true fact with no dependencies', :fact => :true_fact_with_no_dependencies do
|
32
|
+
it_behaves_like 'an accomplished fact', true
|
33
|
+
it_behaves_like 'a possible fact', true
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'given true fact with true dependencies', :fact => :true_fact_with_true_dependencies do
|
37
|
+
it_behaves_like 'an accomplished fact', true
|
38
|
+
it_behaves_like 'a possible fact', true
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'given true fact with false dependencies', :fact => :true_fact_with_false_dependencies do
|
42
|
+
it_behaves_like 'an accomplished fact', false
|
43
|
+
it_behaves_like 'a possible fact', false
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'given false fact with no dependencies', :fact => :false_fact_with_no_dependencies do
|
47
|
+
it_behaves_like 'an accomplished fact', false
|
48
|
+
it_behaves_like 'a possible fact', true
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'given false fact with true dependencies', :fact => :false_fact_with_true_dependencies do
|
52
|
+
it_behaves_like 'an accomplished fact', false
|
53
|
+
it_behaves_like 'a possible fact', true
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'given false fact with false dependencies', :fact => :false_fact_with_false_dependencies do
|
57
|
+
it_behaves_like 'an accomplished fact', false
|
58
|
+
it_behaves_like 'a possible fact', false
|
59
|
+
end
|
60
|
+
|
61
|
+
specify '#facts' do
|
62
|
+
target.facts.size.should == 7
|
63
|
+
end
|
64
|
+
|
65
|
+
specify '#accomplished_facts' do
|
66
|
+
target.accomplished_facts.should == [ :bare_fact, :true_fact_with_no_dependencies, :true_fact_with_true_dependencies ]
|
67
|
+
end
|
68
|
+
|
69
|
+
specify '#possible_facts' do
|
70
|
+
target.possible_facts.should == target.facts - [ :true_fact_with_false_dependencies, :false_fact_with_false_dependencies ]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/spec/spec.rake
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
desc 'Run complete application spec suite'
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
|
8
|
+
spec_tasks = Dir['spec/*/'].map { |d| File.basename(d) }
|
9
|
+
|
10
|
+
spec_tasks.each do |folder|
|
11
|
+
RSpec::Core::RakeTask.new("spec:#{folder}") do |t|
|
12
|
+
t.pattern = "./spec/#{folder}/**/*_spec.rb"
|
13
|
+
t.rspec_opts = %w(--color)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# task 'spec' => spec_tasks.map { |f| "spec:#{f}" }
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
4
|
+
require 'fact_checker'
|
5
|
+
Dir['./spec/support/**/*.rb'].each { |f| require f }
|
6
|
+
|
7
|
+
RSpec.configure do |conf|
|
8
|
+
conf.color_enabled = true
|
9
|
+
conf.treat_symbols_as_metadata_keys_with_true_values = true
|
10
|
+
|
11
|
+
conf.expect_with :rspec, :stdlib
|
12
|
+
conf.mock_with :rspec
|
13
|
+
|
14
|
+
conf.fail_fast = true
|
15
|
+
conf.filter_run :focus => true
|
16
|
+
conf.filter_run_excluding :broken => true
|
17
|
+
conf.run_all_when_everything_filtered = true
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
class ClassWithNoFacts
|
6
|
+
include FactChecker
|
7
|
+
end
|
8
|
+
|
9
|
+
class ClassWithFacts
|
10
|
+
include FactChecker
|
11
|
+
|
12
|
+
def_fact :bare_fact
|
13
|
+
def_fact :true_fact_with_no_dependencies, :if => lambda { true }
|
14
|
+
def_fact :true_fact_with_true_dependencies => :bare_fact, :if => lambda { true }
|
15
|
+
def_fact :true_fact_with_false_dependencies => :false_fact_with_no_dependencies, :if => lambda { true }
|
16
|
+
def_fact :false_fact_with_no_dependencies, :if => lambda { false }
|
17
|
+
def_fact :false_fact_with_true_dependencies => :bare_fact , :if => lambda { false }
|
18
|
+
def_fact :false_fact_with_false_dependencies => :false_fact_with_no_dependencies , :if => lambda { false }
|
19
|
+
end
|
20
|
+
|
21
|
+
class ChildOfClassWithFacts < ClassWithFacts
|
22
|
+
end
|
23
|
+
|
24
|
+
# :another_fact should not creep back to parent classes
|
25
|
+
class GrandChildOfClassWithFacts < ChildOfClassWithFacts
|
26
|
+
def_fact :another_fact
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared_examples 'an accomplished fact' do |true_or_false|
|
4
|
+
specify '#fact_accomplished?' do
|
5
|
+
target.fact_accomplished?(example.metadata[:fact]).should be true_or_false
|
6
|
+
end
|
7
|
+
|
8
|
+
specify '#(:fact)? predicate' do
|
9
|
+
target.send("#{example.metadata[:fact]}?").should be true_or_false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
shared_examples 'a possible fact' do |true_or_false|
|
14
|
+
specify '#fact_possible?' do
|
15
|
+
target.fact_possible?(example.metadata[:fact]).should be true_or_false
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fact_checker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alexey Smolianinov
|
9
|
+
- Ivan Povalyukhin
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2011-10-31 00:00:00.000000000 +04:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec
|
18
|
+
requirement: &84896850 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '2.6'
|
24
|
+
type: :development
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: *84896850
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: &84896660 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ! '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: *84896660
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: bundler
|
40
|
+
requirement: &84896430 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
type: :development
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: *84896430
|
49
|
+
description: Simple gem to check hierarchically dependent "facts" about objects
|
50
|
+
email:
|
51
|
+
- alexisowl+fact_checker@gmail.com
|
52
|
+
executables: []
|
53
|
+
extensions: []
|
54
|
+
extra_rdoc_files: []
|
55
|
+
files:
|
56
|
+
- .gitignore
|
57
|
+
- .rvmrc
|
58
|
+
- Gemfile
|
59
|
+
- README
|
60
|
+
- Rakefile
|
61
|
+
- examples/README.md
|
62
|
+
- examples/basic.rb
|
63
|
+
- fact_checker.gemspec
|
64
|
+
- lib/fact_checker.rb
|
65
|
+
- lib/fact_checker/base.rb
|
66
|
+
- lib/fact_checker/version.rb
|
67
|
+
- spec/fact_checker/base_spec.rb
|
68
|
+
- spec/fact_checker/version_spec.rb
|
69
|
+
- spec/fact_checker_inheritance_spec.rb
|
70
|
+
- spec/fact_checker_spec.rb
|
71
|
+
- spec/spec.rake
|
72
|
+
- spec/spec_helper.rb
|
73
|
+
- spec/support/classes_with_facts.rb
|
74
|
+
- spec/support/shared_facts_behaviour.rb
|
75
|
+
has_rdoc: true
|
76
|
+
homepage: https://github.com/alexis/fact_checker
|
77
|
+
licenses: []
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 1.8.7
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.3.5
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project: fact_checker
|
96
|
+
rubygems_version: 1.6.2
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: Checks facts which may depend on other facts
|
100
|
+
test_files: []
|