cukesalad 0.2.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/.rspec +1 -0
- data/Examples/Calculator/Gemfile +5 -0
- data/Examples/Calculator/Gemfile.lock +66 -0
- data/Examples/Calculator/cucumber.yml +4 -0
- data/Examples/Calculator/features/LOOK_MA_NO_STEP_DEFS.txt +2 -0
- data/Examples/Calculator/features/a_place_to_start.feature +9 -0
- data/Examples/Calculator/features/addition.feature +19 -0
- data/Examples/Calculator/features/complex_calculations.feature +16 -0
- data/Examples/Calculator/features/lib/alternative/roles/calculating_web_user.rb +55 -0
- data/Examples/Calculator/features/lib/default/roles/calculating_individual.rb +32 -0
- data/Examples/Calculator/features/lib/default/tasks/add.rb +13 -0
- data/Examples/Calculator/features/lib/default/tasks/calculate.rb +4 -0
- data/Examples/Calculator/features/lib/default/tasks/calculations.rb +15 -0
- data/Examples/Calculator/features/lib/default/tasks/see_the_answer.rb +3 -0
- data/Examples/Calculator/features/lib/default/tasks/subtract.rb +4 -0
- data/Examples/Calculator/features/lib/default/tasks/switch_on_the_calculator.rb +9 -0
- data/Examples/Calculator/features/subtraction.feature +20 -0
- data/Examples/Calculator/features/support/env.rb +6 -0
- data/Examples/Calculator/features/typical_workflow.feature +18 -0
- data/Examples/Calculator/lib/calculator.rb +53 -0
- data/Examples/Calculator/lib/config.ru +4 -0
- data/Examples/Calculator/lib/web_calculator.rb +82 -0
- data/Examples/Calculator/spec/calculator_spec.rb +73 -0
- data/Examples/Calculator/spec/web_calculator_spec.rb +99 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +47 -0
- data/LICENSE +21 -0
- data/README.md +273 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/cukesalad +28 -0
- data/cucumber.yml +4 -0
- data/cukesalad/cli.rb +68 -0
- data/examples/Calculator/features/lib/alternative/roles/calculating_web_user.rb +55 -0
- data/examples/Calculator/features/lib/default/roles/calculating_individual.rb +32 -0
- data/examples/Calculator/features/lib/default/tasks/add.rb +13 -0
- data/examples/Calculator/features/lib/default/tasks/calculate.rb +4 -0
- data/examples/Calculator/features/lib/default/tasks/calculations.rb +15 -0
- data/examples/Calculator/features/lib/default/tasks/see_the_answer.rb +3 -0
- data/examples/Calculator/features/lib/default/tasks/subtract.rb +4 -0
- data/examples/Calculator/features/lib/default/tasks/switch_on_the_calculator.rb +9 -0
- data/examples/Calculator/features/support/env.rb +6 -0
- data/examples/Calculator/lib/calculator.rb +53 -0
- data/examples/Calculator/lib/web_calculator.rb +82 -0
- data/examples/Calculator/spec/calculator_spec.rb +73 -0
- data/examples/Calculator/spec/web_calculator_spec.rb +99 -0
- data/features/a_new_cukesalad_project.feature +34 -0
- data/features/define_a_role.feature +31 -0
- data/features/define_a_task.feature +55 -0
- data/features/lib/roles/step_free_cuker.rb +5 -0
- data/features/lib/tasks/create_a_file.rb +3 -0
- data/features/lib/tasks/create_a_new_cukesalad_project.rb +11 -0
- data/features/lib/tasks/create_a_role.rb +4 -0
- data/features/lib/tasks/create_a_task.rb +4 -0
- data/features/lib/tasks/create_directories.rb +5 -0
- data/features/lib/tasks/not_create_a_role.rb +2 -0
- data/features/lib/tasks/not_create_a_task.rb +3 -0
- data/features/lib/tasks/run.rb +4 -0
- data/features/lib/tasks/run_a_scenario.rb +7 -0
- data/features/lib/tasks/see_a_reply.rb +3 -0
- data/features/lib/tasks/see_the_step_has.rb +4 -0
- data/features/support/env.rb +7 -0
- data/lib/actor.rb +32 -0
- data/lib/codify/const_name.rb +21 -0
- data/lib/cukesalad.rb +33 -0
- data/lib/director.rb +28 -0
- data/lib/specifics.rb +30 -0
- data/lib/task_author.rb +12 -0
- data/spec/actor_spec.rb +72 -0
- data/spec/codify/as_const_name_spec.rb +28 -0
- data/spec/cukesalad/cli_spec.rb +99 -0
- data/spec/director_spec.rb +34 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/specifics_spec.rb +36 -0
- data/spec/task_author_spec.rb +50 -0
- metadata +202 -0
data/Gemfile.lock
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
aruba (0.3.5)
|
5
|
+
childprocess (>= 0.1.7)
|
6
|
+
cucumber (>= 0.10.0)
|
7
|
+
rspec (>= 2.5.0)
|
8
|
+
builder (3.0.0)
|
9
|
+
childprocess (0.1.7)
|
10
|
+
ffi (~> 0.6.3)
|
11
|
+
cucumber (0.10.0)
|
12
|
+
builder (>= 2.1.2)
|
13
|
+
diff-lcs (~> 1.1.2)
|
14
|
+
gherkin (~> 2.3.2)
|
15
|
+
json (~> 1.4.6)
|
16
|
+
term-ansicolor (~> 1.0.5)
|
17
|
+
diff-lcs (1.1.2)
|
18
|
+
ffi (0.6.3)
|
19
|
+
rake (>= 0.8.7)
|
20
|
+
gherkin (2.3.3)
|
21
|
+
json (~> 1.4.6)
|
22
|
+
git (1.2.5)
|
23
|
+
jeweler (1.5.2)
|
24
|
+
bundler (~> 1.0.0)
|
25
|
+
git (>= 1.2.5)
|
26
|
+
rake
|
27
|
+
json (1.4.6)
|
28
|
+
rake (0.8.7)
|
29
|
+
rspec (2.5.0)
|
30
|
+
rspec-core (~> 2.5.0)
|
31
|
+
rspec-expectations (~> 2.5.0)
|
32
|
+
rspec-mocks (~> 2.5.0)
|
33
|
+
rspec-core (2.5.1)
|
34
|
+
rspec-expectations (2.5.0)
|
35
|
+
diff-lcs (~> 1.1.2)
|
36
|
+
rspec-mocks (2.5.0)
|
37
|
+
term-ansicolor (1.0.5)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
aruba (= 0.3.5)
|
44
|
+
bundler (~> 1.0.0)
|
45
|
+
cucumber (= 0.10.0)
|
46
|
+
jeweler (~> 1.5.2)
|
47
|
+
rspec (= 2.5.0)
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2010 RiverGlide
|
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.
|
21
|
+
|
data/README.md
ADDED
@@ -0,0 +1,273 @@
|
|
1
|
+
# Cuke Salad
|
2
|
+
|
3
|
+
_Cucumber, washed and ready to eat for Friction-free ATDD/BDD_
|
4
|
+
|
5
|
+
**This is a work in progress - feedback welcome**
|
6
|
+
e-mail feedback to <talktous@riverglide.com>
|
7
|
+
|
8
|
+
** ToDo: **
|
9
|
+
|
10
|
+
* Support more step structures - such as tables as input
|
11
|
+
* Move beyond current examples by documenting CukeSalad with Cucumber
|
12
|
+
* Remembering data between steps
|
13
|
+
* Multiple role/actor scenarios
|
14
|
+
|
15
|
+
## This project has step-free access!
|
16
|
+
|
17
|
+
CukeSalad allows you to focus on the task at hand - expressing examples, the roles involved in those examples and what those roles can do with the product under development.
|
18
|
+
|
19
|
+
With CukeSalad you don't need to write step-definitions.
|
20
|
+
|
21
|
+
Of course, you still have to write some code - but only the code that expresses:
|
22
|
+
|
23
|
+
* the roles and the actions they can perform
|
24
|
+
* the tasks and the actions involved in completing that task
|
25
|
+
|
26
|
+
## Goals->Tasks->Actions
|
27
|
+
The terms *"actions"* and *"tasks"* above come from Task Analysis, as used in User Centred Design (UCD) of Human Computer Interfaces (HCI) a.k.a. User Experience (UX):
|
28
|
+
|
29
|
+
* *Goal:* What we’re trying to achieve which has one or more…
|
30
|
+
* *Tasks:* The high-level work-item that we complete to fulfil the goal, each having one or more…
|
31
|
+
* *Actions:* The specific steps or interactions we execute to complete the task.
|
32
|
+
|
33
|
+
More information about Goals, Tasks and Actions can be found in this [blog post](http://antonymarcano.com/blog/2011/03/goals-tasks-action/)
|
34
|
+
|
35
|
+
Let's see how this works with a simple example...
|
36
|
+
|
37
|
+
## Install
|
38
|
+
|
39
|
+
gem install cukesalad
|
40
|
+
|
41
|
+
## Let's Get started
|
42
|
+
|
43
|
+
Create a new project Calculator:
|
44
|
+
|
45
|
+
mkdir Calculator
|
46
|
+
cd Calculator
|
47
|
+
mkdir features
|
48
|
+
mkdir features/support
|
49
|
+
mkdir features/lib
|
50
|
+
mkdir features/lib/tasks
|
51
|
+
mkdir features/lib/roles
|
52
|
+
|
53
|
+
In idiomatic Cucumber style, we use `features/support/env.rb` to require _CukeSalad_:
|
54
|
+
|
55
|
+
require 'cukesalad'
|
56
|
+
begin require 'rspec/expectations'; rescue LoadError; require 'spec/expectations'; end
|
57
|
+
|
58
|
+
Cucumber will automatically find our project's _roles_ and _tasks_, as it loads
|
59
|
+
all .rb files beneath the project's `features/` directory.
|
60
|
+
|
61
|
+
## Write Features
|
62
|
+
|
63
|
+
In `features/`, let's create our first feature file - `a_place_to_start.feature`:
|
64
|
+
|
65
|
+
Feature: A Place To Start
|
66
|
+
As Callie, a calculating individual
|
67
|
+
I want to know when my calculator is on
|
68
|
+
So that I know when I can start calculating
|
69
|
+
|
70
|
+
Scenario: Let's Begin
|
71
|
+
Given I am a Calculating Individual
|
72
|
+
When I attempt to switch on the calculator
|
73
|
+
Then I should see the answer '0'
|
74
|
+
|
75
|
+
Let's take a moment to understand this scenario:
|
76
|
+
|
77
|
+
Scenario: Let's Begin
|
78
|
+
Given I am a <some role>
|
79
|
+
When I attempt to <do some task>
|
80
|
+
Then I should <ask some question> '<expected answer>'
|
81
|
+
|
82
|
+
To get this working, we don't need to write any steps.
|
83
|
+
Just explain how to do the _task_ using a class...
|
84
|
+
|
85
|
+
## Create Tasks
|
86
|
+
|
87
|
+
Explaining how to do a _task_ is easy:
|
88
|
+
Create a new file, `features/lib/tasks/switch_on_the_calculator.rb`
|
89
|
+
|
90
|
+
Remember the step `When I attempt to switch on the calculator`
|
91
|
+
|
92
|
+
in_order_to "SwitchOnTheCalculator" do
|
93
|
+
@calc = switch_on_the_calculator
|
94
|
+
end
|
95
|
+
|
96
|
+
Remember the step `Then I should see the answer '0'`
|
97
|
+
Now we need `task/see_the_answer.rb`
|
98
|
+
|
99
|
+
in_order_to "SeeTheAnswer" do
|
100
|
+
look_at_the_display
|
101
|
+
end
|
102
|
+
|
103
|
+
Now we've explained the _tasks_, we need to define the _role_ that performs them. In
|
104
|
+
this example, we need to explain how the `CalculatingIndividual` _role_ works...
|
105
|
+
|
106
|
+
## Create Roles
|
107
|
+
|
108
|
+
Remember the step `Given I am a Calculating Individual`?
|
109
|
+
|
110
|
+
We explain a _role_ by creating a new file
|
111
|
+
called `features/lib/roles/calculating_individual.rb`
|
112
|
+
|
113
|
+
module CalculatingIndividual
|
114
|
+
|
115
|
+
def switch_on_the_calculator
|
116
|
+
@calculator = Calculator.new
|
117
|
+
end
|
118
|
+
|
119
|
+
def look_at_the_display
|
120
|
+
@calculator.display
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
You'll need a class called Calculator on the load path of course, but that's it.
|
125
|
+
|
126
|
+
From your project folder, run (_note: '%' is our command prompt_)
|
127
|
+
|
128
|
+
% cucumber
|
129
|
+
|
130
|
+
We now have our first passing Feature, without creating a single step definition!
|
131
|
+
|
132
|
+
## Wash, rinse, repeat
|
133
|
+
|
134
|
+
Let's try another scenario...
|
135
|
+
|
136
|
+
Scenario Outline: Find the sum of two numbers
|
137
|
+
Given I am a Calculating Individual
|
138
|
+
And I was able to switch on the calculator
|
139
|
+
When I attempt to add: the number '10' to the number '10'
|
140
|
+
Then I should see the answer '20'
|
141
|
+
|
142
|
+
Notice that we've reused 'switch on the calculator'.
|
143
|
+
|
144
|
+
The new _When_ step has a slightly different layout.
|
145
|
+
Let's examine that for a second... Notice the ':' (colon) after <do something> and the name-value pairs:
|
146
|
+
|
147
|
+
When I attempt to <do something>: <name> '<value>' <name> '<value>'
|
148
|
+
|
149
|
+
You can have as many name-value pairs as you like.
|
150
|
+
|
151
|
+
So, we need a task called `tasks/add.rb` that explains the individual actions required to complete the task:
|
152
|
+
|
153
|
+
in_order_to "Add" do
|
154
|
+
enter @value_of(:the_number)
|
155
|
+
press :plus
|
156
|
+
enter @value_of(:to_the_number)
|
157
|
+
press :equals
|
158
|
+
end
|
159
|
+
|
160
|
+
Notice how the `value_of` lines use symbols that correspond to the wording `'the number '10' to the number '10'` in the "When" step.
|
161
|
+
|
162
|
+
There is some 'syntactic sugar' that we can use to dress this up a little and make it read nicer... a simple attribute mapping:
|
163
|
+
|
164
|
+
in_order_to "Add", the_number: :first_number, to_the_number: :second_number do
|
165
|
+
enter the :first_number
|
166
|
+
press :plus
|
167
|
+
enter the :second_number
|
168
|
+
press :equals
|
169
|
+
end
|
170
|
+
|
171
|
+
All we've done is mapped "the_number" to "first_number". There is a special method called "the" that allows you to reference the mapped values rather than the symbols derived from the scenario.
|
172
|
+
|
173
|
+
Now all we need to do is modify our `calculating_individual.rb` to receive those calls...
|
174
|
+
|
175
|
+
module CalculatingIndividual
|
176
|
+
|
177
|
+
def switch_on_the_calculator
|
178
|
+
@calculator = Calculator.new
|
179
|
+
@operate_with = {
|
180
|
+
plus: :+,
|
181
|
+
minus: :-
|
182
|
+
}
|
183
|
+
end
|
184
|
+
|
185
|
+
def enter value
|
186
|
+
@calculator.enter value.to_i
|
187
|
+
end
|
188
|
+
|
189
|
+
def press next_operator
|
190
|
+
if next_operator == :equals
|
191
|
+
equals
|
192
|
+
else
|
193
|
+
@calculator.get_ready_to @operate_with[next_operator]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def equals
|
198
|
+
@calculator.equals
|
199
|
+
end
|
200
|
+
|
201
|
+
def look_at_the_display
|
202
|
+
@calculator.display
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
Now, you can run cucumber again:
|
207
|
+
|
208
|
+
% cucumber
|
209
|
+
|
210
|
+
There's no need to write `step_definitions`...
|
211
|
+
Simply express the _roles_ and the _tasks_ in clear,
|
212
|
+
concise, easy to read classes.
|
213
|
+
|
214
|
+
After adding some more scenarios and tasks and an alternative "Calculating Individual" (see below for why), our finished Calculator directory structure looks like this...
|
215
|
+
|
216
|
+
├── cucumber.yml
|
217
|
+
├── features
|
218
|
+
│ ├── A_PlaceToStart.feature
|
219
|
+
│ ├── Addition.feature
|
220
|
+
│ ├── Complex_calculations.feature
|
221
|
+
│ ├── LOOK_MA_NO_STEP_DEFS.txt
|
222
|
+
│ ├── Subtraction.feature
|
223
|
+
│ ├── Typical_workflow.feature
|
224
|
+
│ ├── lib
|
225
|
+
│ │ ├── alternative
|
226
|
+
│ │ │ ├── roles
|
227
|
+
│ │ │ │ └── calculating_web_user.rb
|
228
|
+
│ │ │ └── tasks
|
229
|
+
│ │ └── default
|
230
|
+
│ │ ├── roles
|
231
|
+
│ │ │ └── calculating_individual.rb
|
232
|
+
│ │ └── tasks
|
233
|
+
│ │ ├── add.rb
|
234
|
+
│ │ ├── perform.rb
|
235
|
+
│ │ ├── see_the_answer.rb
|
236
|
+
│ │ ├── subtract.rb
|
237
|
+
│ │ └── switch_on_the_calculator.rb
|
238
|
+
│ └── support
|
239
|
+
│ └── env.rb
|
240
|
+
├── lib
|
241
|
+
│ ├── calculator.rb
|
242
|
+
│ └── web_calculator.rb
|
243
|
+
└── spec
|
244
|
+
├── calculator_spec.rb
|
245
|
+
└── web_calculator_spec.rb
|
246
|
+
|
247
|
+
Take a look around the examples and the code to see how it all works. We hope you enjoy reading as much as we enjoyed writing it.
|
248
|
+
|
249
|
+
## Alternative Roles
|
250
|
+
|
251
|
+
As our features _describe the value of a calculator application and not its
|
252
|
+
implementation_, we have the opportunity to reuse them.
|
253
|
+
|
254
|
+
In the Calculator example, we create a new _role_ in
|
255
|
+
`./features/lib/alternative/roles/calculating_web_user.rb`, which we can swap
|
256
|
+
into our tests using a Cucumber profile defined in `features/cucumber.yml`:
|
257
|
+
|
258
|
+
default --exclude features/lib/alternative/
|
259
|
+
alternative -r features/lib/alternative/ -r features/support/env.rb -r features/lib/default/tasks/
|
260
|
+
|
261
|
+
We can run our alternative configuration like so:
|
262
|
+
|
263
|
+
`%cucumber --profile alternative`
|
264
|
+
|
265
|
+
The Calculating Web User masquerades as the Calculating Individual from our
|
266
|
+
previous example, and provides the same API, allowing us to reuse all of our
|
267
|
+
existing features and _tasks_.
|
268
|
+
|
269
|
+
The alternative, `./lib/web_calculator.rb`, implementation is a simple [Sinatra](http://www.sinatrarb.com) application,
|
270
|
+
which we drive with the [Capybara](http://github.com/jnicklas/capybara) web testing framework.
|
271
|
+
|
272
|
+
By writing a single new _role_ class we're able to reuse all of our existing features,
|
273
|
+
_tasks_ and even the `Calculator` itself, which the web calculator delegates to in order to do its calculations.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
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 = "cukesalad"
|
16
|
+
gem.homepage = "https://github.com/RiverGlide/CukeSalad"
|
17
|
+
gem.platform = Gem::Platform::RUBY
|
18
|
+
gem.license = "MIT"
|
19
|
+
gem.summary = %Q{Friction Free BDD/ATDD with cucumber}
|
20
|
+
gem.description = %Q{CukeSalad allows you to focus on the tasks at hand - expressing examples, the roles involved in those examples and the tasks that those roles need to perform with the product under development.}
|
21
|
+
gem.email = "talktous@riverglide.com"
|
22
|
+
gem.authors = ["RiverGlide"]
|
23
|
+
|
24
|
+
# The following two lines need to be commented out in order to gain access to the version rake tasks
|
25
|
+
gem_version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
26
|
+
gem.version = gem_version
|
27
|
+
gem.executables = ["cukesalad"]
|
28
|
+
gem.files.include 'lib/cukesalad/cli.rb'
|
29
|
+
end
|
30
|
+
|
31
|
+
Jeweler::RubygemsDotOrgTasks.new
|
32
|
+
|
33
|
+
require 'rspec/core'
|
34
|
+
require 'rspec/core/rake_task'
|
35
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
36
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
37
|
+
spec.rspec_opts = "-cfd"
|
38
|
+
end
|
39
|
+
|
40
|
+
require 'cucumber/rake/task'
|
41
|
+
Cucumber::Rake::Task.new(:cucumber)
|
42
|
+
|
43
|
+
task :default => :spec
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "CukeSalad #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0
|
data/bin/cukesalad
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'cukesalad/cli'
|
5
|
+
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.banner = "Usage: cukesalad [new | configure] project_name"
|
8
|
+
|
9
|
+
begin
|
10
|
+
opts.parse!(ARGV)
|
11
|
+
rescue OptionParser::ParseError => e
|
12
|
+
warn e.message
|
13
|
+
puts opts
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
if ARGV.empty?
|
19
|
+
abort "Usage: cukesalad new <project name>\nOr: cukesalad configure"
|
20
|
+
elsif ARGV.first == 'new'
|
21
|
+
project = ARGV[1]
|
22
|
+
puts "Creating project #{project}..."
|
23
|
+
CukeSalad::CLI.create_new_project project
|
24
|
+
puts "Done!"
|
25
|
+
elsif ARGV.first == 'configure'
|
26
|
+
CukeSalad::CLI.configure_existing_project
|
27
|
+
puts "Done!"
|
28
|
+
end
|
data/cucumber.yml
ADDED
data/cukesalad/cli.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'aruba/api'
|
2
|
+
module CukeSalad
|
3
|
+
class CLI
|
4
|
+
|
5
|
+
def self.create_new_project project
|
6
|
+
structure = Structure.new
|
7
|
+
structure.setup project
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.configure_existing_project project=nil
|
11
|
+
`cd #{project}` if project
|
12
|
+
structure = Structure.new
|
13
|
+
structure.setup_cucumber_with_cukesalad
|
14
|
+
end
|
15
|
+
|
16
|
+
class Structure
|
17
|
+
include Aruba::Api
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
set_aruba_path_to_current
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup project
|
24
|
+
create_and_navigate_to project
|
25
|
+
setup_cucumber_with_cukesalad
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup_cucumber_with_cukesalad
|
29
|
+
create_dir_structure
|
30
|
+
configure
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def set_aruba_path_to_current
|
35
|
+
@dirs = ["./"]
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_dir_structure
|
39
|
+
create_cucumber_structure
|
40
|
+
create_cukesalad_structure
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_cucumber_structure
|
44
|
+
create_and_navigate_to "features"
|
45
|
+
create_dir "support"
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_cukesalad_structure
|
49
|
+
create_and_navigate_to "lib"
|
50
|
+
create_and_navigate_to "default"
|
51
|
+
create_dir "roles"
|
52
|
+
create_dir "tasks"
|
53
|
+
cd "../../../"
|
54
|
+
end
|
55
|
+
|
56
|
+
def configure
|
57
|
+
cd "features/support"
|
58
|
+
content = "require 'cukesalad'\n begin require 'rspec/expectations'; rescue LoadError; require 'spec/expectations'; end"
|
59
|
+
append_to_file "env.rb",content
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_and_navigate_to directory
|
63
|
+
create_dir directory
|
64
|
+
cd directory
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# To run with this version of the Calculating Individual:
|
2
|
+
# cucumber --profile alternative
|
3
|
+
|
4
|
+
require 'web_calculator'
|
5
|
+
require 'capybara'
|
6
|
+
require 'capybara/dsl'
|
7
|
+
|
8
|
+
Capybara.app = WebCalculator
|
9
|
+
Capybara.default_driver = :rack_test
|
10
|
+
|
11
|
+
module CalculatingIndividual
|
12
|
+
|
13
|
+
# Uses a Browser to perform its tasks
|
14
|
+
include Capybara
|
15
|
+
# This is not a page object. It is a WebUser, specialised to our application
|
16
|
+
# See the comments in the 'enter' and 'press' method for an explanation of why
|
17
|
+
|
18
|
+
def switch_on_the_calculator
|
19
|
+
visit '/'
|
20
|
+
end
|
21
|
+
|
22
|
+
def enter value
|
23
|
+
fill_in 'number', :with => value
|
24
|
+
# Because the calculator is a simple web_app with only
|
25
|
+
# one page we can put the id for the field here. In a more complex web-app
|
26
|
+
# we would pass in the id of the thing to enter
|
27
|
+
# The task would express the action as: enter( :the_number, "10")
|
28
|
+
# Because we can change the id used in our application,
|
29
|
+
# we would just change the id in the application to be 'the_number'.
|
30
|
+
# If we were on a project where we could not change the id
|
31
|
+
# in the application we would write an 'ApplicationExpert'
|
32
|
+
# to map :the_number to the id for the field 'number'. Our CalculatingIndividual
|
33
|
+
# would ask the ApplicationExpert for the id of the symbol :the_number
|
34
|
+
# See 'press' below for am explanation of how an ApplicationExpert
|
35
|
+
# would work
|
36
|
+
end
|
37
|
+
|
38
|
+
def press operator
|
39
|
+
click_button operator.to_s
|
40
|
+
# Here, our 'operator' happens to also match the id for the button.
|
41
|
+
# If we were on a project where we could not choose what the id
|
42
|
+
# was for buttons, we would write an ApplicationExpert to map
|
43
|
+
# the symbol used in the task to the symbol for that button.
|
44
|
+
# The ApplicationExpert would only need to know what page it
|
45
|
+
# was on to find a mappings class (or yml file) for the fields on that page.
|
46
|
+
end
|
47
|
+
|
48
|
+
def look_at_the_display
|
49
|
+
find_field('display').value.to_i
|
50
|
+
end
|
51
|
+
|
52
|
+
def is_the_calculator_ready?
|
53
|
+
page.body.should =~ /Calculator is Ready!/
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'calculator'
|
2
|
+
|
3
|
+
module CalculatingIndividual
|
4
|
+
|
5
|
+
def switch_on_the_calculator
|
6
|
+
@calculator = Calculator.new
|
7
|
+
@operate_with = {
|
8
|
+
plus: :+,
|
9
|
+
minus: :-
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def enter value
|
14
|
+
@calculator.enter value.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def press next_operator
|
18
|
+
if next_operator == :equals
|
19
|
+
equals
|
20
|
+
else
|
21
|
+
@calculator.get_ready_to @operate_with[next_operator]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def equals
|
26
|
+
@calculator.equals
|
27
|
+
end
|
28
|
+
|
29
|
+
def look_at_the_display
|
30
|
+
@calculator.display
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# This demonstrates how to use an attribute mapping
|
2
|
+
# to make the interactions within the task read more naturally
|
3
|
+
# In the scenario it might say "add: the number '5', to the number '10'
|
4
|
+
# The form illustrated below simply maps the elements the_number and to_the_number
|
5
|
+
# to alternative symbols that make the interactions read more like real instructions
|
6
|
+
# See subtract.rb for a way of writing tasks that reuses the common interactions
|
7
|
+
# required to perform calculations.
|
8
|
+
in_order_to 'add', the_number: :first_number, to_the_number: :second_number do
|
9
|
+
enter the :first_number
|
10
|
+
press :plus
|
11
|
+
enter the :second_number
|
12
|
+
press :equals
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Calculations
|
2
|
+
|
3
|
+
def follow_the_steps_for sum
|
4
|
+
enter_numbers_and_operators_for sum
|
5
|
+
end
|
6
|
+
|
7
|
+
def enter_numbers_and_operators_for sum
|
8
|
+
operator = {"+" => :plus, "-" => :minus, "=" => :equals}
|
9
|
+
sum.each do | token |
|
10
|
+
enter token.to_i if token =~ /\d+/
|
11
|
+
press operator[token] if operator.include? token
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,6 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../../lib') #where to find the calculator implementation
|
2
|
+
$:.unshift(File.dirname(__FILE__) + '/../../../../lib') #where to find CukeSalad
|
3
|
+
|
4
|
+
require 'cukesalad'
|
5
|
+
|
6
|
+
begin require 'rspec/expectations'; rescue LoadError; require 'spec/expectations'; end
|