ruler 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +59 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/bin/example.rb +44 -0
- data/lib/ruler.rb +133 -0
- data/spec/ruler_spec.rb +191 -0
- data/spec/spec_helper.rb +12 -0
- metadata +154 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "rspec", "~> 2.3.0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.5.2"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
gem "mocha"
|
14
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Joshua Smith
|
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.
|
data/README.rdoc
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
= ruler
|
2
|
+
|
3
|
+
Ruler is a simple module providing a DSL that helps with defining facts and rules. While ruler is not a prolog or a
|
4
|
+
full-fledged production rule system, it might become one someday.
|
5
|
+
|
6
|
+
== How To Use It
|
7
|
+
|
8
|
+
You use it whenever you would have a long set of nested if/else blocks or other kinds of conditional logic.
|
9
|
+
require 'rubygems'
|
10
|
+
require 'ruler'
|
11
|
+
class TeaDrinker
|
12
|
+
include Ruler
|
13
|
+
attr_accessor :tea
|
14
|
+
|
15
|
+
def make_iced_tea
|
16
|
+
puts "Making tea"
|
17
|
+
end
|
18
|
+
|
19
|
+
def drink_iced_tea
|
20
|
+
puts "Ahhhhhhh"
|
21
|
+
end
|
22
|
+
|
23
|
+
def thirsty?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def tea_check outside_temp
|
28
|
+
ruleset do
|
29
|
+
fact :it_is_hot, outside_temp >= 100.0
|
30
|
+
fact :iced_tea_made, true
|
31
|
+
fact :no_iced_tea, notf(:iced_tea_made)
|
32
|
+
fact :am_thirsty, self.thirsty?
|
33
|
+
|
34
|
+
rule [:it_is_hot, :am_thirsty, :no_iced_tea] do
|
35
|
+
make_iced_tea
|
36
|
+
end
|
37
|
+
|
38
|
+
rule [:it_is_hot, :am_thirsty, :iced_tea_made] do
|
39
|
+
drink_iced_tea
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
== Contributing to ruler
|
46
|
+
|
47
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
48
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
49
|
+
* Fork the project
|
50
|
+
* Start a feature/bugfix branch
|
51
|
+
* Commit and push until you are happy with your contribution
|
52
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
53
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
54
|
+
|
55
|
+
== Copyright
|
56
|
+
|
57
|
+
Copyright (c) 2011 Joshua Smith. See LICENSE.txt for
|
58
|
+
further details.
|
59
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "ruler"
|
16
|
+
gem.homepage = "http://github.com/BlueFrogGaming/ruler"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{Ruby DSL to help with rules and facts}
|
19
|
+
gem.description = %Q{Longer description of your gem}
|
20
|
+
gem.email = "kognate@gmail.com"
|
21
|
+
gem.authors = ["Joshua Smith"]
|
22
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
23
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
24
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
25
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
26
|
+
end
|
27
|
+
Jeweler::RubygemsDotOrgTasks.new
|
28
|
+
|
29
|
+
require 'rspec/core'
|
30
|
+
require 'rspec/core/rake_task'
|
31
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
32
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
33
|
+
end
|
34
|
+
|
35
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
36
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
37
|
+
spec.rcov = true
|
38
|
+
end
|
39
|
+
|
40
|
+
task :default => :spec
|
41
|
+
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
45
|
+
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
rdoc.title = "ruler #{version}"
|
48
|
+
rdoc.rdoc_files.include('README*')
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/bin/example.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'lib/ruler'
|
4
|
+
|
5
|
+
class TeaDrinker
|
6
|
+
include Ruler
|
7
|
+
attr_accessor :tea
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@DEBUG = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def make_iced_tea
|
14
|
+
puts "Making tea"
|
15
|
+
end
|
16
|
+
|
17
|
+
def drink_iced_tea
|
18
|
+
puts "Ahhhhhhh"
|
19
|
+
end
|
20
|
+
|
21
|
+
def thirsty?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def tea_check outside_temp
|
26
|
+
ruleset do
|
27
|
+
fact :it_is_hot do outside_temp >= 100.0 end
|
28
|
+
fact :iced_tea_made, true
|
29
|
+
fact :no_iced_tea, notf(:iced_tea_made)
|
30
|
+
fact :am_thirsty, self.thirsty?
|
31
|
+
|
32
|
+
rule [:it_is_hot, :am_thirsty, :no_iced_tea] do
|
33
|
+
make_iced_tea
|
34
|
+
end
|
35
|
+
|
36
|
+
rule [:it_is_hot, :am_thirsty, :iced_tea_made] do
|
37
|
+
drink_iced_tea
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
t = TeaDrinker.new
|
44
|
+
puts t.tea_check 190.0
|
data/lib/ruler.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
# This module provides a set of methods to manage and run sets of facts and rules.
|
2
|
+
# These rules take an array of fact names and all of the facts are true
|
3
|
+
# the block passed to the rule is executed. By default, only one rule can fire in a given ruleset.
|
4
|
+
# Each ruleset can have a default_rule which is executed if no rule fires (and the ruleset only allows
|
5
|
+
# one rule to fire)
|
6
|
+
|
7
|
+
# Author:: Josh Smith (josh@bluefroggaming.com)
|
8
|
+
# Copyright:: (c) 2011 Blue Frog Gaming, All Rights Reserved
|
9
|
+
# License:: This file has no public license.
|
10
|
+
|
11
|
+
class BadDefaultRule < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
module Ruler
|
15
|
+
# This module uses thread local storage and should be threadsafe.
|
16
|
+
#
|
17
|
+
# A ruleset is the method that wraps all calls to fact and rule.
|
18
|
+
# A ruleset takes two arguments, the first is a boolean that determins if
|
19
|
+
# more than one rule can fire. If this value is true, that ruleset allows only one
|
20
|
+
# rule to fire (this is the default). If this value is false, all rules that evaluate to
|
21
|
+
# true will fire. rulesets can also include a default_rule, which behaves as a normal rule
|
22
|
+
# that is always true. The default_rule obeys the ruleset's singletary status
|
23
|
+
# A short example:
|
24
|
+
#
|
25
|
+
# result = ruleset do
|
26
|
+
# fact :is_true, true
|
27
|
+
# fact :water_is_wet, true
|
28
|
+
# fact :cannot_push_on_a_rope, true
|
29
|
+
#
|
30
|
+
# fact :do_not_mess_with_jim do
|
31
|
+
# false
|
32
|
+
# end
|
33
|
+
# fact :pi_greater_than_four do
|
34
|
+
# Math::PI > 4
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# rule [:is_true, :water_is_wet, :do_not_mess_with_jim] do
|
38
|
+
# rand()
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# rule [:cannot_push_on_a_rope, :water_is_wet, :is_true] do
|
42
|
+
# 42
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# default_rule do
|
46
|
+
# 100
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
# puts result
|
50
|
+
|
51
|
+
def ruleset singletary = true,&blk
|
52
|
+
Thread.current[:singletary] = singletary
|
53
|
+
Thread.current[:rulematched] = nil
|
54
|
+
Thread.current[:working_memory] = {}
|
55
|
+
yield
|
56
|
+
end
|
57
|
+
|
58
|
+
# multi_ruleset is a helper function to define rulesets that allow
|
59
|
+
# more than one rule to fire
|
60
|
+
def multi_ruleset &blk
|
61
|
+
ruleset false,&blk
|
62
|
+
end
|
63
|
+
|
64
|
+
# a fact takes a symbol name and either a value or a block.
|
65
|
+
# for example:
|
66
|
+
# fact :factname, true
|
67
|
+
# fact :otherfactname do
|
68
|
+
# some_computation_that_evaluates_to_true_or_false
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# Facts may be defined anywhere in the ruleset. due to the
|
72
|
+
# evaluation order, facts that appear after the last rule
|
73
|
+
# will never be used.
|
74
|
+
def fact name, dval = nil, &blk
|
75
|
+
if dval.nil?
|
76
|
+
Thread.current[:working_memory][name] = yield
|
77
|
+
else
|
78
|
+
Thread.current[:working_memory][name] = dval
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# allows for a fact to be NOT another fact.
|
84
|
+
# for example:
|
85
|
+
# fact :one, 10 == 10
|
86
|
+
# fact :notfone, not(:one)
|
87
|
+
def notf name
|
88
|
+
not(Thread.current[:working_memory][name])
|
89
|
+
end
|
90
|
+
|
91
|
+
# a rule takes a list of fact names and a block. Rules are evaluated in the order
|
92
|
+
# they appear in the ruleset and are evaluated at execution time. If all of the facts are true, then
|
93
|
+
# that rule is fired. If the ruleset is singletary, only one rule (the first rule to be true)
|
94
|
+
# may fire.
|
95
|
+
# rules may also have docstrings. These aren't really used yet,
|
96
|
+
# but they will be and they provide a nice alternative to commenting.
|
97
|
+
# For example:
|
98
|
+
# rule [:one_fact, :two_facts], "this is the docstring" do
|
99
|
+
# some_method
|
100
|
+
# end
|
101
|
+
# there is no check to see if fact names are valid, and facts can be (re)defined
|
102
|
+
#inside of rules. Fact names are false if they are not defined.
|
103
|
+
def rule vlist,docstr = nil,&blk
|
104
|
+
dbg = lambda {|va| puts "|=-\t#{va} = #{Thread.current[:working_memory][va]}" }
|
105
|
+
if @DEBUG
|
106
|
+
puts "---------------------------------------"
|
107
|
+
puts vlist.join(" & ")
|
108
|
+
puts "======================================="
|
109
|
+
vlist.each {|v| dbg.call(v) }
|
110
|
+
puts "---------------------------------------"
|
111
|
+
end
|
112
|
+
if Thread.current[:singletary] && Thread.current[:rulematched]
|
113
|
+
Thread.current[:rulematched]
|
114
|
+
else
|
115
|
+
|
116
|
+
Thread.current[:rulematched] = if vlist.inject(true) {|k,v| k ? k && Thread.current[:working_memory][v] : false }
|
117
|
+
yield
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# the default_rule is simple a rule that is always true. This is mostly syntactic-sugar to represent
|
123
|
+
# a rule that should fire if no others fire. You cannot have a default rule if you allow more
|
124
|
+
# than one match. The BadDefaultRule exception is raised.
|
125
|
+
def default_rule &blk
|
126
|
+
raise BadDefaultRule.new("Can't have a default rule when multiple matches are allowed") unless Thread.current[:singletary]
|
127
|
+
if Thread.current[:singletary] && !Thread.current[:rulematched]
|
128
|
+
yield
|
129
|
+
else
|
130
|
+
Thread.current[:rulematched]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/spec/ruler_spec.rb
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require 'ruler'
|
3
|
+
|
4
|
+
class Rules
|
5
|
+
include Ruler
|
6
|
+
def initialize
|
7
|
+
#@DEBUG = true
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_one
|
11
|
+
ruleset do
|
12
|
+
|
13
|
+
fact :firstone, true
|
14
|
+
|
15
|
+
rule [:firstone] do
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
default_rule do
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_two
|
26
|
+
ruleset do
|
27
|
+
fact :firstone, true
|
28
|
+
|
29
|
+
rule [:firstone] do
|
30
|
+
self.should_fire
|
31
|
+
"this should be here"
|
32
|
+
end
|
33
|
+
|
34
|
+
rule [:firstone] do
|
35
|
+
self.should_not_fire
|
36
|
+
"this should not be here"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_three
|
43
|
+
ruleset do
|
44
|
+
|
45
|
+
fact :firstone, true
|
46
|
+
fact :secondone, true
|
47
|
+
fact :thirdone, false
|
48
|
+
fact :fourthone, (1 == 1)
|
49
|
+
fact :fifthone, (2 == 2)
|
50
|
+
fact :sixthone, true
|
51
|
+
|
52
|
+
rule [:firstone,:secondone,:thirdone, :fourthone, :fifthone] do
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
rule [:firstone,:secondone,:sixthone, :fourthone, :fifthone] do
|
57
|
+
true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_four
|
63
|
+
ruleset do
|
64
|
+
fact :firstone do
|
65
|
+
true || true || false
|
66
|
+
end
|
67
|
+
fact :secondone, true
|
68
|
+
fact :thirdone, true
|
69
|
+
|
70
|
+
rule [:firstone, :secondone, :thirdone] do
|
71
|
+
true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_five
|
77
|
+
ruleset do
|
78
|
+
fact :firstone, false
|
79
|
+
|
80
|
+
rule [:firstone] do
|
81
|
+
false
|
82
|
+
end
|
83
|
+
|
84
|
+
default_rule do
|
85
|
+
true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_six
|
91
|
+
ruleset do
|
92
|
+
fact :firstone, false
|
93
|
+
fact :secondone, notf(:firstone)
|
94
|
+
|
95
|
+
rule [:secondone] do
|
96
|
+
true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_seven
|
102
|
+
multi_ruleset do
|
103
|
+
fact :firstone, true
|
104
|
+
fact :secondone, true
|
105
|
+
|
106
|
+
rule [:firstone] do
|
107
|
+
self.test_seven_multi
|
108
|
+
true
|
109
|
+
end
|
110
|
+
|
111
|
+
rule [:secondone] do
|
112
|
+
self.test_seven_multi
|
113
|
+
true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_eight
|
119
|
+
ruleset do
|
120
|
+
fact :firstone, true
|
121
|
+
|
122
|
+
rule [:firstone],"""
|
123
|
+
This is the documentation for this rule.
|
124
|
+
It can be on multiple lines if you
|
125
|
+
do it right. This is a ruby limitation,
|
126
|
+
I think.
|
127
|
+
""" do
|
128
|
+
true
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_nine
|
134
|
+
multi_ruleset do
|
135
|
+
default_rule do
|
136
|
+
true
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe Rules do
|
143
|
+
it "should process a simple rule" do
|
144
|
+
r = Rules.new
|
145
|
+
r.test_one.should be(true)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should only process the first matching rule" do
|
149
|
+
r = Rules.new
|
150
|
+
r.expects(:should_fire)
|
151
|
+
r.test_two.should == "this should be here"
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should process rules with several conditions" do
|
155
|
+
r = Rules.new
|
156
|
+
r.test_three.should be(true)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should handle ORs" do
|
160
|
+
r = Rules.new
|
161
|
+
r.test_four.should be(true)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should respect the default rule" do
|
165
|
+
r = Rules.new
|
166
|
+
r.test_five.should be(true)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should run correctly with notf" do
|
170
|
+
r = Rules.new
|
171
|
+
r.test_six.should be(true)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should run multi_rulesets" do
|
175
|
+
r = Rules.new
|
176
|
+
r.expects(:test_seven_multi).twice
|
177
|
+
r.test_seven.should be(true)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should run even with docstrings" do
|
181
|
+
r = Rules.new
|
182
|
+
r.test_eight.should be(true)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should throw if there is a defualt rule in a multimatch" do
|
186
|
+
r = Rules.new
|
187
|
+
lambda { r.test_nine.should}.should raise_error
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'ruler'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.mock_with :mocha
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Joshua Smith
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-31 00:00:00 -05:00
|
19
|
+
default_executable: example.rb
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 2
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
version: 2.3.0
|
34
|
+
name: rspec
|
35
|
+
requirement: *id001
|
36
|
+
type: :development
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 23
|
45
|
+
segments:
|
46
|
+
- 1
|
47
|
+
- 0
|
48
|
+
- 0
|
49
|
+
version: 1.0.0
|
50
|
+
name: bundler
|
51
|
+
requirement: *id002
|
52
|
+
type: :development
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
prerelease: false
|
55
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 7
|
61
|
+
segments:
|
62
|
+
- 1
|
63
|
+
- 5
|
64
|
+
- 2
|
65
|
+
version: 1.5.2
|
66
|
+
name: jeweler
|
67
|
+
requirement: *id003
|
68
|
+
type: :development
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 3
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
name: rcov
|
81
|
+
requirement: *id004
|
82
|
+
type: :development
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
name: mocha
|
95
|
+
requirement: *id005
|
96
|
+
type: :development
|
97
|
+
description: Longer description of your gem
|
98
|
+
email: kognate@gmail.com
|
99
|
+
executables:
|
100
|
+
- example.rb
|
101
|
+
extensions: []
|
102
|
+
|
103
|
+
extra_rdoc_files:
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.rdoc
|
106
|
+
files:
|
107
|
+
- .document
|
108
|
+
- .rspec
|
109
|
+
- Gemfile
|
110
|
+
- LICENSE.txt
|
111
|
+
- README.rdoc
|
112
|
+
- Rakefile
|
113
|
+
- VERSION
|
114
|
+
- bin/example.rb
|
115
|
+
- lib/ruler.rb
|
116
|
+
- spec/ruler_spec.rb
|
117
|
+
- spec/spec_helper.rb
|
118
|
+
has_rdoc: true
|
119
|
+
homepage: http://github.com/BlueFrogGaming/ruler
|
120
|
+
licenses:
|
121
|
+
- MIT
|
122
|
+
post_install_message:
|
123
|
+
rdoc_options: []
|
124
|
+
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
hash: 3
|
133
|
+
segments:
|
134
|
+
- 0
|
135
|
+
version: "0"
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
hash: 3
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
version: "0"
|
145
|
+
requirements: []
|
146
|
+
|
147
|
+
rubyforge_project:
|
148
|
+
rubygems_version: 1.3.7
|
149
|
+
signing_key:
|
150
|
+
specification_version: 3
|
151
|
+
summary: Ruby DSL to help with rules and facts
|
152
|
+
test_files:
|
153
|
+
- spec/ruler_spec.rb
|
154
|
+
- spec/spec_helper.rb
|