lime 0.1.0
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 +7 -0
- data/.ruby +51 -0
- data/.yardopts +7 -0
- data/Assembly +46 -0
- data/COPYING.rdoc +59 -0
- data/LICENSE.txt +25 -0
- data/MANIFEST +12 -0
- data/PROFILE +29 -0
- data/README.md +65 -0
- data/VERSION +1 -0
- data/lib/lime.rb +28 -0
- data/lib/lime/advice.rb +31 -0
- data/lib/lime/feature.rb +251 -0
- data/lib/lime/scenario.rb +160 -0
- data/lib/lime/step.rb +64 -0
- data/lime.gemspec +152 -0
- data/try/.testrb +3 -0
- data/try/calculator.rb +15 -0
- data/try/feature_example.rb +40 -0
- metadata +129 -0
data/.gitignore
ADDED
data/.ruby
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
---
|
2
|
+
authors:
|
3
|
+
- name: Thomas Sawyer
|
4
|
+
email: transfire@gmail.com
|
5
|
+
copyrights:
|
6
|
+
- holder: Thomas Sawyer
|
7
|
+
year: "2011"
|
8
|
+
license: BSD-2-Clause
|
9
|
+
replacements: []
|
10
|
+
|
11
|
+
conflicts: []
|
12
|
+
|
13
|
+
requirements:
|
14
|
+
- name: test
|
15
|
+
- name: ae
|
16
|
+
- name: detroit
|
17
|
+
groups:
|
18
|
+
- build
|
19
|
+
development: true
|
20
|
+
- name: reap
|
21
|
+
groups:
|
22
|
+
- build
|
23
|
+
development: true
|
24
|
+
- name: qed
|
25
|
+
groups:
|
26
|
+
- test
|
27
|
+
development: true
|
28
|
+
dependencies: []
|
29
|
+
|
30
|
+
repositories:
|
31
|
+
- uri: git://github.com/proutils/lime.git
|
32
|
+
scm: git
|
33
|
+
name: upstream
|
34
|
+
resources:
|
35
|
+
home: http://rubyworks.github.com/lime
|
36
|
+
code: http://github.com/rubyworks/lime
|
37
|
+
mail: http://groups.google.com/group/rubyworks-mailinglist
|
38
|
+
load_path:
|
39
|
+
- lib
|
40
|
+
extra:
|
41
|
+
manifest: MANIFEST
|
42
|
+
alternatives: []
|
43
|
+
|
44
|
+
revision: 0
|
45
|
+
title: Lime
|
46
|
+
suite: RubyWorks
|
47
|
+
summary: Gherkin-style Test Framework
|
48
|
+
description: Lime is a "Ruby DSL" knock-off of Cucumber's Gherkin BDD nomenclature that runs on top of ruby-test.
|
49
|
+
version: 0.1.0
|
50
|
+
name: lime
|
51
|
+
date: "2011-07-29"
|
data/.yardopts
ADDED
data/Assembly
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
---
|
2
|
+
github:
|
3
|
+
active: true
|
4
|
+
|
5
|
+
gem:
|
6
|
+
active: true
|
7
|
+
|
8
|
+
dnote:
|
9
|
+
labels: ~
|
10
|
+
output: log/NOTES.rdoc
|
11
|
+
|
12
|
+
yard:
|
13
|
+
yardopts: true
|
14
|
+
|
15
|
+
qed:
|
16
|
+
files : ~
|
17
|
+
#exclude : ~
|
18
|
+
#loadpath: ~
|
19
|
+
#requires: ~
|
20
|
+
#live : false
|
21
|
+
active : false
|
22
|
+
|
23
|
+
qedoc:
|
24
|
+
files : spec/
|
25
|
+
output: QED.rdoc
|
26
|
+
active: false
|
27
|
+
|
28
|
+
vclog:
|
29
|
+
output: log/ChangeLog.rdoc
|
30
|
+
active: false
|
31
|
+
|
32
|
+
email:
|
33
|
+
service: Email
|
34
|
+
file : ~
|
35
|
+
subject: ~
|
36
|
+
mailto :
|
37
|
+
- ruby-talk@ruby-lang.org
|
38
|
+
- rubyworks-mailinglist@googlegroups.com
|
39
|
+
from : <%= ENV['EMAIL_ACCOUNT'] %>
|
40
|
+
server : <%= ENV['EMAIL_SERVER'] %>
|
41
|
+
port : <%= ENV['EMAIL_PORT'] %>
|
42
|
+
account: <%= ENV['EMAIL_ACCOUNT'] %>
|
43
|
+
domain : <%= ENV['EMAIL_DOMAIN'] %>
|
44
|
+
login : <%= ENV['EMAIL_LOGIN'] %>
|
45
|
+
secure : <%= ENV['EMAIL_SECURE'] %>
|
46
|
+
|
data/COPYING.rdoc
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
= COPYRIGHT NOTICES
|
2
|
+
|
3
|
+
== Lime Test Framework
|
4
|
+
|
5
|
+
Copyright:: (c) 2011 Thomas Sawyer, RubyWorks
|
6
|
+
License:: BSD-2-Clause
|
7
|
+
Website:: http://rubyworks.github.com/ruby-test
|
8
|
+
|
9
|
+
Copyright 2011 Thomas Sawyer. All rights reserved.
|
10
|
+
|
11
|
+
Redistribution and use in source and binary forms, with or without
|
12
|
+
modification, are permitted provided that the following conditions are met:
|
13
|
+
|
14
|
+
1. Redistributions of source code must retain the above copyright notice,
|
15
|
+
this list of conditions and the following disclaimer.
|
16
|
+
|
17
|
+
2. Redistributions in binary form must reproduce the above copyright
|
18
|
+
notice, this list of conditions and the following disclaimer in the
|
19
|
+
documentation and/or other materials provided with the distribution.
|
20
|
+
|
21
|
+
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
22
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
23
|
+
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
24
|
+
COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
25
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
26
|
+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
27
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
28
|
+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
29
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
30
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
|
32
|
+
|
33
|
+
== Gherkin
|
34
|
+
|
35
|
+
Copyright:: (c) 2009-2011 Mike Sassak, Gregory Hnatiuk, Aslak Hellesøy
|
36
|
+
License:: MIT
|
37
|
+
Website:: https://github.com/cucumber/gherkin
|
38
|
+
|
39
|
+
Copyright (c) 2009-2011 Mike Sassak, Gregory Hnatiuk, Aslak Hellesøy
|
40
|
+
|
41
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
42
|
+
a copy of this software and associated documentation files (the
|
43
|
+
"Software"), to deal in the Software without restriction, including
|
44
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
45
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
46
|
+
permit persons to whom the Software is furnished to do so, subject to
|
47
|
+
the following conditions:
|
48
|
+
|
49
|
+
The above copyright notice and this permission notice shall be
|
50
|
+
included in all copies or substantial portions of the Software.
|
51
|
+
|
52
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
53
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
54
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
55
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
56
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
57
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
58
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
59
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
BSD 2 Clause License
|
2
|
+
|
3
|
+
Copyright 2011 Thomas Sawyer. All rights reserved.
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
7
|
+
|
8
|
+
1. Redistributions of source code must retain the above copyright notice,
|
9
|
+
this list of conditions and the following disclaimer.
|
10
|
+
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright
|
12
|
+
notice, this list of conditions and the following disclaimer in the
|
13
|
+
documentation and/or other materials provided with the distribution.
|
14
|
+
|
15
|
+
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
16
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
18
|
+
COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
19
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
20
|
+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
21
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
22
|
+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
23
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
24
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
|
data/MANIFEST
ADDED
data/PROFILE
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
---
|
2
|
+
title : Lime
|
3
|
+
suite : RubyWorks
|
4
|
+
summary: Gherkin-style Test Framework
|
5
|
+
authors:
|
6
|
+
- Thomas Sawyer <transfire@gmail.com>
|
7
|
+
|
8
|
+
description:
|
9
|
+
Lime is a "Ruby DSL" knock-off of Cucumber's Gherkin
|
10
|
+
BDD nomenclature that runs on top of ruby-test.
|
11
|
+
|
12
|
+
resources:
|
13
|
+
home: http://rubyworks.github.com/lime
|
14
|
+
code: http://github.com/rubyworks/lime
|
15
|
+
mail: http://groups.google.com/group/rubyworks-mailinglist
|
16
|
+
|
17
|
+
repositories:
|
18
|
+
upstream: git://github.com/proutils/lime.git
|
19
|
+
|
20
|
+
copyrights:
|
21
|
+
- 2011 Thomas Sawyer (BSD-2-Clause)
|
22
|
+
|
23
|
+
requirements:
|
24
|
+
- test
|
25
|
+
- ae
|
26
|
+
- detroit (build)
|
27
|
+
- reap (build)
|
28
|
+
- qed (test)
|
29
|
+
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Lime
|
2
|
+
|
3
|
+
Author:: Thomas Sawyer
|
4
|
+
License:: FreeBSD
|
5
|
+
Copyright:: (c) 2011 Thomas Sawyer, Rubyworks
|
6
|
+
|
7
|
+
|
8
|
+
## Description
|
9
|
+
|
10
|
+
Lime is pure Ruby Gherkin-style test framework.
|
11
|
+
|
12
|
+
|
13
|
+
## Example
|
14
|
+
|
15
|
+
``` ruby
|
16
|
+
Feature "Addition" do
|
17
|
+
To "avoid silly mistakes"
|
18
|
+
As "a math idiot"
|
19
|
+
We "need to calculate the sum of numbers"
|
20
|
+
|
21
|
+
Scenario "Add two numbers" do
|
22
|
+
Given "I have a calculator"
|
23
|
+
Given "I have entered 50 into the calculator"
|
24
|
+
Given "I have entered 70 into the calculator"
|
25
|
+
When "I press add"
|
26
|
+
Then "the result should be 120 on the screen"
|
27
|
+
end
|
28
|
+
|
29
|
+
Scenario "Add three numbers" do
|
30
|
+
Given "I have a calculator"
|
31
|
+
Given "I have entered 50 into the calculator"
|
32
|
+
Given "I have entered 70 into the calculator"
|
33
|
+
Given "I have entered 90 into the calculator"
|
34
|
+
When "I press add"
|
35
|
+
Then "the result should be 2101 on the screen"
|
36
|
+
end
|
37
|
+
|
38
|
+
Given 'I have a calculator' do
|
39
|
+
require 'calculator'
|
40
|
+
@calculator = Calculator.new
|
41
|
+
end
|
42
|
+
|
43
|
+
Given 'I have entered (((\d+))) into the calculator' do |n|
|
44
|
+
@calculator.push n.to_i
|
45
|
+
end
|
46
|
+
|
47
|
+
When 'I press add' do
|
48
|
+
@result = @calculator.add
|
49
|
+
end
|
50
|
+
|
51
|
+
Then 'the result should be (((\d+))) on the screen' do |n|
|
52
|
+
@result.assert == n.to_i
|
53
|
+
end
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
|
58
|
+
## Copyrights
|
59
|
+
|
60
|
+
Copyright (c) 2011 Thomas Sawyer, Rubyworks
|
61
|
+
|
62
|
+
Lime is distributed according to the terms of the *FreeBSD* license.
|
63
|
+
|
64
|
+
See COPYING.rdoc for details.
|
65
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/lime.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Lime
|
2
|
+
$TEST_SUITE ||= []
|
3
|
+
|
4
|
+
require 'lime/advice'
|
5
|
+
require 'lime/feature'
|
6
|
+
require 'lime/scenario'
|
7
|
+
require 'lime/step'
|
8
|
+
end
|
9
|
+
|
10
|
+
# Ignore lime paths in backtraces
|
11
|
+
ignore_path = File.expand_path(File.dirname(__FILE__) + '/lime')
|
12
|
+
ignore_regexp = Regexp.new(Regexp.escape(ignore_path))
|
13
|
+
RUBY_IGNORE_CALLERS = [] unless defined? RUBY_IGNORE_CALLERS
|
14
|
+
RUBY_IGNORE_CALLERS << ignore_regexp
|
15
|
+
RUBY_IGNORE_CALLERS << /bin\/ruby-test/
|
16
|
+
|
17
|
+
module Test
|
18
|
+
extend self
|
19
|
+
|
20
|
+
# Define a general test case.
|
21
|
+
def Feature(label, &block)
|
22
|
+
$TEST_SUITE << Lime::Feature.new(:label=>label, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
alias :feature :Feature
|
26
|
+
end
|
27
|
+
|
28
|
+
extend Test
|
data/lib/lime/advice.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Lime
|
2
|
+
|
3
|
+
# Test Advice
|
4
|
+
class Advice
|
5
|
+
|
6
|
+
#
|
7
|
+
attr :table
|
8
|
+
|
9
|
+
# New case instance.
|
10
|
+
def initialize
|
11
|
+
@table = Hash.new{ |h,k| h[k] = {} }
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
def initialize_copy(original)
|
16
|
+
@table = original.table.clone
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
def [](type)
|
21
|
+
@table[type.to_sym]
|
22
|
+
end
|
23
|
+
|
24
|
+
## Returns the description with newlines removed.
|
25
|
+
#def to_s
|
26
|
+
# description.gsub(/\n/, ' ')
|
27
|
+
#end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/lib/lime/feature.rb
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
#require 'lime/pending'
|
2
|
+
require 'lime/advice'
|
3
|
+
require 'lime/scenario'
|
4
|
+
|
5
|
+
module Lime
|
6
|
+
|
7
|
+
# The TestFeature ...
|
8
|
+
#
|
9
|
+
# The `advice` are _given_, _when_ and _then_ rules.
|
10
|
+
#
|
11
|
+
class Feature
|
12
|
+
|
13
|
+
# Brief description of the feature.
|
14
|
+
attr :label
|
15
|
+
|
16
|
+
#
|
17
|
+
attr :story
|
18
|
+
|
19
|
+
# List of tests and sub-cases.
|
20
|
+
attr :scenarios
|
21
|
+
|
22
|
+
# Advice are labeled procedures, such as before
|
23
|
+
# and after advice.
|
24
|
+
attr :advice
|
25
|
+
|
26
|
+
# Module for evaluating tests.
|
27
|
+
attr :scope
|
28
|
+
|
29
|
+
#
|
30
|
+
def initialize(settings={}, &block)
|
31
|
+
@label = settings[:label]
|
32
|
+
@setup = settings[:setup]
|
33
|
+
|
34
|
+
@advice = Advice.new
|
35
|
+
@scope = Module.new
|
36
|
+
|
37
|
+
@story = []
|
38
|
+
@scenarios = []
|
39
|
+
|
40
|
+
@scope.extend DSL.new(self, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Convenience method for accessing advice, aka step definitions.
|
44
|
+
def [](key)
|
45
|
+
@advice[key]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Iterate over each scenario.
|
49
|
+
def each(&block)
|
50
|
+
scenarios.each(&block)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Number of scenarios.
|
54
|
+
def size
|
55
|
+
scenarios.size
|
56
|
+
end
|
57
|
+
|
58
|
+
# Subclasses of TestCase can override this to describe
|
59
|
+
# the type of test case they define.
|
60
|
+
def type
|
61
|
+
'Feature'
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
def to_s
|
66
|
+
(["#{label}"] + story).join("\n")
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
def omit?
|
71
|
+
@omit
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
def omit=(boolean)
|
76
|
+
@omit = boolean
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
def update(mixin)
|
81
|
+
@advice[:given].concat mixin[:given] || []
|
82
|
+
@advice[:when].concat mixin[:when] || []
|
83
|
+
@advice[:then].concat mixin[:then] || []
|
84
|
+
@scope.extend mixin if Module === mixin
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
class DSL < Module
|
89
|
+
|
90
|
+
#
|
91
|
+
def initialize(feature, &code)
|
92
|
+
@_feature = feature
|
93
|
+
|
94
|
+
module_eval(&code)
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
def To(description)
|
99
|
+
@_feature.story << "To " + description
|
100
|
+
end
|
101
|
+
alias_method :to, :To
|
102
|
+
|
103
|
+
#
|
104
|
+
def As(description)
|
105
|
+
@_feature.story << "As " + description
|
106
|
+
end
|
107
|
+
alias_method :as, :As
|
108
|
+
|
109
|
+
#
|
110
|
+
def We(description)
|
111
|
+
@_feature.story << "We " + description
|
112
|
+
end
|
113
|
+
alias_method :we, :We
|
114
|
+
|
115
|
+
#
|
116
|
+
def Scenario(label, &procedure)
|
117
|
+
scenario = Scenario.new(@_feature, :label=>label, &procedure)
|
118
|
+
@_feature.scenarios << scenario
|
119
|
+
scenario
|
120
|
+
end
|
121
|
+
alias_method :scenario, :Scenario
|
122
|
+
|
123
|
+
# Omit a scenario from test runs.
|
124
|
+
#
|
125
|
+
# omit unit :foo do
|
126
|
+
# # ...
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
def Omit(scenario)
|
130
|
+
scenario.omit = true
|
131
|
+
end
|
132
|
+
alias_method :omit, :Omit
|
133
|
+
|
134
|
+
# Given ...
|
135
|
+
#
|
136
|
+
# @param [String] description
|
137
|
+
# A brief description of the _given_ criteria.
|
138
|
+
#
|
139
|
+
def Given(description, &procedure)
|
140
|
+
@_feature[:given][description] = procedure
|
141
|
+
end
|
142
|
+
alias_method :given, :Given
|
143
|
+
|
144
|
+
# When ...
|
145
|
+
#
|
146
|
+
# @param [String] description
|
147
|
+
# A brief description of the _when_ criteria.
|
148
|
+
#
|
149
|
+
def When(description, &procedure)
|
150
|
+
@_feature[:when][description] = procedure
|
151
|
+
end
|
152
|
+
alias_method :wence, :When
|
153
|
+
|
154
|
+
# Then ...
|
155
|
+
#
|
156
|
+
# @param [String] description
|
157
|
+
# A brief description of the _then_ criteria.
|
158
|
+
#
|
159
|
+
def Then(description, &procedure)
|
160
|
+
@_feature[:then][description] = procedure
|
161
|
+
end
|
162
|
+
alias_method :hence, :Then
|
163
|
+
|
164
|
+
#
|
165
|
+
def _feature
|
166
|
+
@_feature
|
167
|
+
end
|
168
|
+
|
169
|
+
#
|
170
|
+
def include(mixin)
|
171
|
+
if Featurable === mixin
|
172
|
+
@_feature.update(mixin)
|
173
|
+
super(mixin)
|
174
|
+
else
|
175
|
+
super(mixin)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
# Convenience method for creating a feature mixin.
|
182
|
+
#
|
183
|
+
# @example
|
184
|
+
#
|
185
|
+
# module MySteps
|
186
|
+
# include Lime::Featurable
|
187
|
+
# Given "customer's name is '(((\s+)))'" do |name|
|
188
|
+
# @name = name
|
189
|
+
# end
|
190
|
+
# end
|
191
|
+
#
|
192
|
+
# Feature do
|
193
|
+
# include MySteps
|
194
|
+
# end
|
195
|
+
#
|
196
|
+
module Featurable
|
197
|
+
|
198
|
+
def self.append_features(base)
|
199
|
+
base.extend(self)
|
200
|
+
base.module_eval %{
|
201
|
+
@_advice = Hash.new { |h,k| h[k]={} }
|
202
|
+
}
|
203
|
+
end
|
204
|
+
|
205
|
+
#
|
206
|
+
#def initialize(&code)
|
207
|
+
# @_advice = Hash.new { |h,k| h[k]={} }
|
208
|
+
#
|
209
|
+
# module_eval(&code)
|
210
|
+
#end
|
211
|
+
|
212
|
+
# Given ...
|
213
|
+
#
|
214
|
+
# @param [String] description
|
215
|
+
# A brief description of the _given_ criteria.
|
216
|
+
#
|
217
|
+
def Given(description, &procedure)
|
218
|
+
@_advice[:given][description] = procedure
|
219
|
+
end
|
220
|
+
alias_method :given, :Given
|
221
|
+
|
222
|
+
# When ...
|
223
|
+
#
|
224
|
+
# @param [String] description
|
225
|
+
# A brief description of the _when_ criteria.
|
226
|
+
#
|
227
|
+
def When(description, &procedure)
|
228
|
+
@_advice[:when][description] = procedure
|
229
|
+
end
|
230
|
+
alias_method :wence, :When
|
231
|
+
|
232
|
+
# Then ...
|
233
|
+
#
|
234
|
+
# @param [String] description
|
235
|
+
# A brief description of the _then_ criteria.
|
236
|
+
#
|
237
|
+
def Then(description, &procedure)
|
238
|
+
@_advice[:then][description] = procedure
|
239
|
+
end
|
240
|
+
alias_method :hence, :Then
|
241
|
+
|
242
|
+
# Access to internal feature instance.
|
243
|
+
def [](key)
|
244
|
+
@_advice[key]
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'lime/step'
|
2
|
+
|
3
|
+
module Lime
|
4
|
+
|
5
|
+
#
|
6
|
+
class Scenario
|
7
|
+
|
8
|
+
#
|
9
|
+
def initialize(feature, settings={}, &block)
|
10
|
+
@feature = feature
|
11
|
+
|
12
|
+
@label = settings[:label]
|
13
|
+
|
14
|
+
@scope = Module.new
|
15
|
+
|
16
|
+
@steps = []
|
17
|
+
|
18
|
+
@scope.extend DSL.new(self, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
attr :feature
|
23
|
+
|
24
|
+
#
|
25
|
+
attr :label
|
26
|
+
|
27
|
+
#
|
28
|
+
attr :steps
|
29
|
+
|
30
|
+
#
|
31
|
+
attr :scope
|
32
|
+
|
33
|
+
#
|
34
|
+
def omit?
|
35
|
+
@omit
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
def omit=(boolean)
|
40
|
+
@omit = boolean
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
def each(&block)
|
45
|
+
@steps.each(&block)
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
def size(&block)
|
50
|
+
@steps.size
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
def type
|
55
|
+
"Scenario"
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
def to_s
|
60
|
+
@label.to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
# FIXME
|
64
|
+
def subject
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
def run(step)
|
69
|
+
type = step.type
|
70
|
+
desc = step.label
|
71
|
+
feature.advice[type].each do |mask, proc|
|
72
|
+
if md = match_regexp(mask).match(desc)
|
73
|
+
scope.instance_exec(*md[1..-1], &proc)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
#--
|
80
|
+
# TODO: Change so that the scope is the DSL
|
81
|
+
# and includes the DSL of the context?
|
82
|
+
#++
|
83
|
+
#def scope
|
84
|
+
# @scope ||= (
|
85
|
+
# #if feature
|
86
|
+
# # scope = feature.scope || Object.new
|
87
|
+
# # scope.extend(dsl)
|
88
|
+
# #else
|
89
|
+
# scope = Object.new
|
90
|
+
# scope.extend(dsl)
|
91
|
+
# #end
|
92
|
+
# )
|
93
|
+
#end
|
94
|
+
|
95
|
+
#
|
96
|
+
#def find
|
97
|
+
# features.clauses[@type].find{ |c| c =~ @description }
|
98
|
+
#end
|
99
|
+
|
100
|
+
# Convert matching string into a regular expression. If the string
|
101
|
+
# contains double parenthesis, such as ((.*?)), then the text within
|
102
|
+
# them is treated as in regular expression and kept verbatium.
|
103
|
+
#
|
104
|
+
# TODO: Better way to isolate regexp. Maybe ?:(.*?) or /(.*?)/.
|
105
|
+
#
|
106
|
+
def match_regexp(str)
|
107
|
+
str = str.split(/(\(\(.*?\)\))(?!\))/).map{ |x|
|
108
|
+
x =~ /\A\(\((.*)\)\)\Z/ ? $1 : Regexp.escape(x)
|
109
|
+
}.join
|
110
|
+
str = str.gsub(/\\\s+/, '\s+')
|
111
|
+
Regexp.new(str, Regexp::IGNORECASE)
|
112
|
+
end
|
113
|
+
|
114
|
+
# TODO: Need to ensure the correct order of Given, When, Then.
|
115
|
+
class DSL < Module
|
116
|
+
|
117
|
+
#
|
118
|
+
def initialize(scenario, &code)
|
119
|
+
@scenario = scenario
|
120
|
+
|
121
|
+
extend(scenario.feature.scope)
|
122
|
+
|
123
|
+
module_eval(&code)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Given ...
|
127
|
+
#
|
128
|
+
# @param [String] description
|
129
|
+
# A matching description of the _given_ procedure.
|
130
|
+
#
|
131
|
+
def Given(label)
|
132
|
+
@scenario.steps << Step.new(@scenario, label, :type=>:given)
|
133
|
+
end
|
134
|
+
alias_method :given, :Given
|
135
|
+
|
136
|
+
# When ...
|
137
|
+
#
|
138
|
+
# @param [String] label
|
139
|
+
# A matching description of the _when_ procedure.
|
140
|
+
#
|
141
|
+
def When(label)
|
142
|
+
@scenario.steps << Step.new(@scenario, label, :type=>:when)
|
143
|
+
end
|
144
|
+
alias_method :wence, :When
|
145
|
+
|
146
|
+
# Then ...
|
147
|
+
#
|
148
|
+
# @param [String] label
|
149
|
+
# A matching description of the _then_ procedure.
|
150
|
+
#
|
151
|
+
def Then(label)
|
152
|
+
@scenario.steps << Step.new(@scenario, label, :type=>:then)
|
153
|
+
end
|
154
|
+
alias_method :hence, :Then
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
data/lib/lime/step.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Lime
|
2
|
+
|
3
|
+
# Test step.
|
4
|
+
#
|
5
|
+
class Step
|
6
|
+
|
7
|
+
# New unit test procedure.
|
8
|
+
#
|
9
|
+
def initialize(scenario, label, settings={})
|
10
|
+
@scenario = scenario
|
11
|
+
@label = label
|
12
|
+
|
13
|
+
@type = settings[:type]
|
14
|
+
|
15
|
+
@omit = false
|
16
|
+
#@tested = false
|
17
|
+
end
|
18
|
+
|
19
|
+
# The type of step (:given, :when or :then).
|
20
|
+
attr :type
|
21
|
+
|
22
|
+
# The scenario to which this step belongs.
|
23
|
+
attr :scenario
|
24
|
+
|
25
|
+
# Label of test.
|
26
|
+
attr :label
|
27
|
+
|
28
|
+
#
|
29
|
+
def omit?
|
30
|
+
@omit
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
def omit=(boolean)
|
35
|
+
@omit = boolean
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
def to_s
|
40
|
+
"#{type.to_s.capitalize} #{label}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# FIXME
|
44
|
+
def subject
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
def to_proc
|
49
|
+
lambda{ call }
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
#def match?(match)
|
54
|
+
# match == target || match === label
|
55
|
+
#end
|
56
|
+
|
57
|
+
#
|
58
|
+
def call
|
59
|
+
scenario.run(self)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/lime.gemspec
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gemspec|
|
6
|
+
|
7
|
+
manifest = Dir.glob('manifest{,.txt)', File::FNM_CASEFOLD).first
|
8
|
+
|
9
|
+
scm = case
|
10
|
+
when File.directory?('.git')
|
11
|
+
:git
|
12
|
+
end
|
13
|
+
|
14
|
+
files = case
|
15
|
+
when manifest
|
16
|
+
File.readlines(manifest).
|
17
|
+
map{ |line| line.srtip }.
|
18
|
+
reject{ |line| line.empty? || line[0,1] == '#' }
|
19
|
+
when scm == :git
|
20
|
+
`git ls-files -z`.split("\0")
|
21
|
+
else
|
22
|
+
Dir.glob('{**/}{.*,*}') # TODO: be more specific using standard locations ?
|
23
|
+
end.select{ |path| File.file?(path) }
|
24
|
+
|
25
|
+
patterns = {
|
26
|
+
:bin_files => 'bin/*',
|
27
|
+
:lib_files => 'lib/{**/}*.rb',
|
28
|
+
:ext_files => 'ext/{**/}extconf.rb',
|
29
|
+
:doc_files => '*.{txt,rdoc,md,markdown,tt,textile}',
|
30
|
+
:test_files => '{test/{**/}*_test.rb,spec/{**/}*_spec.rb}'
|
31
|
+
}
|
32
|
+
|
33
|
+
glob_files = lambda { |pattern|
|
34
|
+
Dir.glob(pattern).select { |path|
|
35
|
+
File.file?(path) && files.include?(path)
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
#files = glob_files[patterns[:files]]
|
40
|
+
|
41
|
+
executables = glob_files[patterns[:bin_files]].map do |path|
|
42
|
+
File.basename(path)
|
43
|
+
end
|
44
|
+
|
45
|
+
extensions = glob_files[patterns[:ext_files]].map do |path|
|
46
|
+
File.basename(path)
|
47
|
+
end
|
48
|
+
|
49
|
+
metadata = YAML.load_file('.ruby')
|
50
|
+
|
51
|
+
# build-out the gemspec
|
52
|
+
|
53
|
+
case metadata['revision']
|
54
|
+
when 0
|
55
|
+
gemspec.name = metadata['name']
|
56
|
+
gemspec.version = metadata['version']
|
57
|
+
gemspec.summary = metadata['summary']
|
58
|
+
gemspec.description = metadata['description']
|
59
|
+
|
60
|
+
metadata['authors'].each do |author|
|
61
|
+
gemspec.authors << author['name']
|
62
|
+
|
63
|
+
if author.has_key?('email')
|
64
|
+
if gemspec.email
|
65
|
+
gemspec.email << author['email']
|
66
|
+
else
|
67
|
+
gemspec.email = [author['email']]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
gemspec.licenses = metadata['licenses']
|
73
|
+
|
74
|
+
metadata['requirements'].each do |req|
|
75
|
+
name = req['name']
|
76
|
+
version = req['version']
|
77
|
+
groups = req['groups'] || []
|
78
|
+
|
79
|
+
if md = /^(.*?)([+-~])$/.match(version)
|
80
|
+
version = case md[2]
|
81
|
+
when '+' then ">= #{$1}"
|
82
|
+
when '-' then "< #{$1}"
|
83
|
+
when '~' then "~> #{$1}"
|
84
|
+
else version
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
#development = req['development']
|
89
|
+
#if development
|
90
|
+
# # populate development dependencies
|
91
|
+
# if gemspec.respond_to?(:add_development_dependency)
|
92
|
+
# gemspec.add_development_dependency(name,*version)
|
93
|
+
# else
|
94
|
+
# gemspec.add_dependency(name,*version)
|
95
|
+
# end
|
96
|
+
#else
|
97
|
+
# # populate runtime dependencies
|
98
|
+
# if gemspec.respond_to?(:add_runtime_dependency)
|
99
|
+
# gemspec.add_runtime_dependency(name,*version)
|
100
|
+
# else
|
101
|
+
# gemspec.add_dependency(name,*version)
|
102
|
+
# end
|
103
|
+
#end
|
104
|
+
|
105
|
+
if groups.empty? or groups.include?('runtime')
|
106
|
+
# populate runtime dependencies
|
107
|
+
if gemspec.respond_to?(:add_runtime_dependency)
|
108
|
+
gemspec.add_runtime_dependency(name,*version)
|
109
|
+
else
|
110
|
+
gemspec.add_dependency(name,*version)
|
111
|
+
end
|
112
|
+
else
|
113
|
+
# populate development dependencies
|
114
|
+
if gemspec.respond_to?(:add_development_dependency)
|
115
|
+
gemspec.add_development_dependency(name,*version)
|
116
|
+
else
|
117
|
+
gemspec.add_dependency(name,*version)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# convert external dependencies into a requirements
|
123
|
+
if metadata['external_dependencies']
|
124
|
+
##gemspec.requirements = [] unless metadata['external_dependencies'].empty?
|
125
|
+
metadata['external_dependencies'].each do |req|
|
126
|
+
gemspec.requirements << req.to_s
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# determine homepage from resources
|
131
|
+
homepage = metadata['resources'].find{ |key, url| key =~ /^home/ }
|
132
|
+
gemspec.homepage = homepage.last if homepage
|
133
|
+
|
134
|
+
gemspec.require_paths = metadata['load_path'] || ['lib']
|
135
|
+
gemspec.post_install_message = metadata['install_message']
|
136
|
+
|
137
|
+
# RubyGems specific metadata
|
138
|
+
gemspec.files = files
|
139
|
+
gemspec.extensions = extensions
|
140
|
+
gemspec.executables = executables
|
141
|
+
|
142
|
+
if Gem::VERSION < '1.7.'
|
143
|
+
gemspec.default_executable = gemspec.executables.first
|
144
|
+
end
|
145
|
+
|
146
|
+
gemspec.test_files = glob_files[patterns[:test_files]]
|
147
|
+
|
148
|
+
unless gemspec.files.include?('.document')
|
149
|
+
gemspec.extra_rdoc_files = glob_files[patterns[:doc_files]]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/try/.testrb
ADDED
data/try/calculator.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
Test::Feature "Addition" do
|
2
|
+
To "avoid silly mistakes"
|
3
|
+
As "a math idiot"
|
4
|
+
We "need to calculate the sum of numbers"
|
5
|
+
|
6
|
+
Scenario "Add two numbers" do
|
7
|
+
Given "I have a calculator"
|
8
|
+
Given "I have entered 50 into the calculator"
|
9
|
+
Given "I have entered 70 into the calculator"
|
10
|
+
When "I press add"
|
11
|
+
Then "the result should be 120 on the screen"
|
12
|
+
end
|
13
|
+
|
14
|
+
Scenario "Add three numbers" do
|
15
|
+
Given "I have a calculator"
|
16
|
+
Given "I have entered 50 into the calculator"
|
17
|
+
Given "I have entered 70 into the calculator"
|
18
|
+
Given "I have entered 90 into the calculator"
|
19
|
+
When "I press add"
|
20
|
+
Then "the result should be 210 on the screen"
|
21
|
+
end
|
22
|
+
|
23
|
+
Given 'I have a calculator' do
|
24
|
+
require 'calculator'
|
25
|
+
@calculator = Calculator.new
|
26
|
+
end
|
27
|
+
|
28
|
+
Given 'I have entered (((\d+))) into the calculator' do |n|
|
29
|
+
@calculator.push n.to_i
|
30
|
+
end
|
31
|
+
|
32
|
+
When 'I press add' do
|
33
|
+
@result = @calculator.add
|
34
|
+
end
|
35
|
+
|
36
|
+
Then 'the result should be (((\d+))) on the screen' do |n|
|
37
|
+
@result.assert == n.to_i
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lime
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas Sawyer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-07-29 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: test
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: ae
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: detroit
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id003
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: reap
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
type: :development
|
58
|
+
version_requirements: *id004
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: qed
|
61
|
+
prerelease: false
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
type: :development
|
69
|
+
version_requirements: *id005
|
70
|
+
description: Lime is a "Ruby DSL" knock-off of Cucumber's Gherkin BDD nomenclature that runs on top of ruby-test.
|
71
|
+
email:
|
72
|
+
- transfire@gmail.com
|
73
|
+
executables: []
|
74
|
+
|
75
|
+
extensions: []
|
76
|
+
|
77
|
+
extra_rdoc_files:
|
78
|
+
- LICENSE.txt
|
79
|
+
- COPYING.rdoc
|
80
|
+
- README.md
|
81
|
+
files:
|
82
|
+
- .gitignore
|
83
|
+
- .ruby
|
84
|
+
- .yardopts
|
85
|
+
- Assembly
|
86
|
+
- COPYING.rdoc
|
87
|
+
- LICENSE.txt
|
88
|
+
- MANIFEST
|
89
|
+
- PROFILE
|
90
|
+
- README.md
|
91
|
+
- VERSION
|
92
|
+
- lib/lime.rb
|
93
|
+
- lib/lime/advice.rb
|
94
|
+
- lib/lime/feature.rb
|
95
|
+
- lib/lime/scenario.rb
|
96
|
+
- lib/lime/step.rb
|
97
|
+
- lime.gemspec
|
98
|
+
- try/.testrb
|
99
|
+
- try/calculator.rb
|
100
|
+
- try/feature_example.rb
|
101
|
+
homepage: http://rubyworks.github.com/lime
|
102
|
+
licenses: []
|
103
|
+
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: "0"
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: "0"
|
121
|
+
requirements: []
|
122
|
+
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 1.8.2
|
125
|
+
signing_key:
|
126
|
+
specification_version: 3
|
127
|
+
summary: Gherkin-style Test Framework
|
128
|
+
test_files: []
|
129
|
+
|