cukesalad 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/.gitignore +1 -0
  2. data/Examples/Calculator/Gemfile +1 -1
  3. data/Examples/Calculator/Gemfile.lock +26 -25
  4. data/Examples/Calculator/README.md +17 -0
  5. data/Examples/Calculator/features/addition.feature +0 -1
  6. data/Examples/Calculator/features/complex_calculations.feature +0 -1
  7. data/Examples/Calculator/features/lib/alternative/roles/calculating_web_user.rb +4 -21
  8. data/Examples/Calculator/features/lib/default/roles/calculating_individual.rb +4 -0
  9. data/Examples/Calculator/features/lib/default/tasks/arithmetic/calculate.rb +1 -1
  10. data/Examples/Calculator/features/subtraction.feature +0 -1
  11. data/Examples/Calculator/features/typical_workflow.feature +0 -1
  12. data/Gemfile.lock +31 -11
  13. data/Rakefile +21 -1
  14. data/VERSION +1 -1
  15. data/cucumber.yml +2 -0
  16. data/cukesalad.gemspec +7 -1
  17. data/features/README.markdown +299 -0
  18. data/features/{a_new_cukesalad_project.feature → creating_a_new_project.feature} +1 -1
  19. data/features/define_a_role.feature +0 -1
  20. data/features/define_a_task.feature +1 -2
  21. data/features/define_a_task_with_arguments.feature +15 -7
  22. data/features/expressing_expectations.feature +39 -0
  23. data/features/lib/roles/step_free_cuker.rb +15 -0
  24. data/features/lib/tasks/create_a_new_cukesalad_project.rb +2 -10
  25. data/features/lib/tasks/create_a_task.rb +9 -9
  26. data/features/prepare_the_actor_for_the_role.feature +36 -0
  27. data/features/remember_information_between_steps.feature +0 -1
  28. data/lib/cukesalad.rb +1 -1
  29. data/lib/cukesalad/actor.rb +7 -1
  30. data/lib/cukesalad/{cucumber.rb → cucumber_steps.rb} +5 -1
  31. data/lib/cukesalad/director.rb +2 -2
  32. data/lib/cukesalad/specifics.rb +2 -2
  33. data/lib/cukesalad/version.rb +1 -1
  34. data/spec/cukesalad/specifics_spec.rb +30 -23
  35. metadata +26 -8
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  .rvmrc
2
2
  *.swp
3
+ *.swo
3
4
  .DS_Store
4
5
 
5
6
  #rdoc generated
@@ -1,5 +1,5 @@
1
1
  source :rubygems
2
- gem "cukesalad", ">=0.6"
2
+ gem "cukesalad", ">=0.7"
3
3
  gem "rspec", ">=2.5.0", :require => 'spec'
4
4
  gem "capybara", ">=0.4.1.2"
5
5
  gem "sinatra", ">=1.2.0"
@@ -1,56 +1,57 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- aruba (0.3.6)
5
- childprocess (>= 0.1.7)
6
- cucumber (>= 0.10.0)
7
- rspec (>= 2.5.0)
4
+ aruba (0.4.3)
5
+ bcat (>= 0.6.1)
6
+ childprocess (>= 0.1.9)
7
+ cucumber (>= 0.10.7)
8
+ rdiscount (>= 1.6.8)
9
+ rspec (>= 2.6.0)
10
+ bcat (0.6.1)
11
+ rack (~> 1.0)
8
12
  builder (3.0.0)
9
- capybara (0.4.1.2)
10
- celerity (>= 0.7.9)
11
- culerity (>= 0.2.4)
13
+ capybara (1.0.0)
12
14
  mime-types (>= 1.16)
13
15
  nokogiri (>= 1.3.3)
14
16
  rack (>= 1.0.0)
15
17
  rack-test (>= 0.5.4)
16
- selenium-webdriver (>= 0.0.27)
17
- xpath (~> 0.1.3)
18
- celerity (0.8.9)
18
+ selenium-webdriver (~> 0.2.0)
19
+ xpath (~> 0.1.4)
19
20
  childprocess (0.1.9)
20
21
  ffi (~> 1.0.6)
21
- cucumber (0.10.2)
22
+ cucumber (1.0.0)
22
23
  builder (>= 2.1.2)
23
24
  diff-lcs (>= 1.1.2)
24
- gherkin (>= 2.3.5)
25
+ gherkin (~> 2.4.1)
25
26
  json (>= 1.4.6)
26
27
  term-ansicolor (>= 1.0.5)
27
- cukesalad (0.6.1)
28
+ cukesalad (0.7.0)
28
29
  aruba (>= 0.3.5)
29
30
  cucumber (>= 0.10.0)
30
31
  rspec (>= 2.5.0)
31
- culerity (0.2.15)
32
32
  diff-lcs (1.1.2)
33
- ffi (1.0.8)
34
- gherkin (2.3.8)
33
+ ffi (1.0.9)
34
+ gherkin (2.4.1)
35
35
  json (>= 1.4.6)
36
- json (1.5.1)
37
- json_pure (1.5.1)
36
+ json (1.5.3)
37
+ json_pure (1.5.3)
38
38
  mime-types (1.16)
39
- nokogiri (1.4.4)
40
- rack (1.2.2)
39
+ nokogiri (1.5.0)
40
+ rack (1.3.0)
41
41
  rack-test (0.6.0)
42
42
  rack (>= 1.0)
43
+ rdiscount (1.6.8)
43
44
  rspec (2.6.0)
44
45
  rspec-core (~> 2.6.0)
45
46
  rspec-expectations (~> 2.6.0)
46
47
  rspec-mocks (~> 2.6.0)
47
- rspec-core (2.6.0)
48
+ rspec-core (2.6.4)
48
49
  rspec-expectations (2.6.0)
49
50
  diff-lcs (~> 1.1.2)
50
51
  rspec-mocks (2.6.0)
51
52
  rubyzip (0.9.4)
52
- selenium-webdriver (0.2.0)
53
- childprocess (>= 0.1.7)
53
+ selenium-webdriver (0.2.2)
54
+ childprocess (>= 0.1.9)
54
55
  ffi (>= 1.0.7)
55
56
  json_pure
56
57
  rubyzip
@@ -58,7 +59,7 @@ GEM
58
59
  rack (~> 1.1)
59
60
  tilt (< 2.0, >= 1.2.2)
60
61
  term-ansicolor (1.0.5)
61
- tilt (1.3)
62
+ tilt (1.3.2)
62
63
  xpath (0.1.4)
63
64
  nokogiri (~> 1.3)
64
65
 
@@ -67,6 +68,6 @@ PLATFORMS
67
68
 
68
69
  DEPENDENCIES
69
70
  capybara (>= 0.4.1.2)
70
- cukesalad (>= 0.6)
71
+ cukesalad (>= 0.7)
71
72
  rspec (>= 2.5.0)
72
73
  sinatra (>= 1.2.0)
@@ -0,0 +1,17 @@
1
+ ## Calculator Example
2
+
3
+ In the current folder...
4
+
5
+ Setup the environment:
6
+
7
+ bundle install
8
+
9
+ Then you can run the examples:
10
+
11
+ bundle exec cucumber
12
+
13
+ To run these via a web front end, use:
14
+
15
+ bundle exec cucumber -p alternative
16
+
17
+ Enjoy!!
@@ -5,7 +5,6 @@ Feature: Addition
5
5
 
6
6
  Scenario Outline: Find the sum of two numbers
7
7
  Given I am a Calculating Individual
8
- And I was able to switch on the calculator
9
8
  When I attempt to add: the number '<first_number>' and the number '<second_number>'
10
9
  Then I should see the answer '<result>'
11
10
 
@@ -5,7 +5,6 @@ Feature: Complex Calculations
5
5
 
6
6
  Scenario Outline: Get the result of a more complex calculation
7
7
  Given I am a calculating individual
8
- And I was able to switch on the calculator
9
8
  When I attempt to calculate, with the following '<calculation>'
10
9
  Then I should see the answer '<correct_result>'
11
10
 
@@ -10,10 +10,11 @@ Capybara.default_driver = :rack_test
10
10
 
11
11
  module CalculatingIndividual
12
12
 
13
- # Uses a Browser to perform its tasks
14
13
  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
14
+
15
+ def role_preparation
16
+ switch_on_the_calculator
17
+ end
17
18
 
18
19
  def switch_on_the_calculator
19
20
  visit '/'
@@ -21,28 +22,10 @@ module CalculatingIndividual
21
22
 
22
23
  def enter value
23
24
  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
25
  end
37
26
 
38
27
  def press operator
39
28
  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
29
  end
47
30
 
48
31
  def look_at_the_display
@@ -2,6 +2,10 @@ require 'calculator'
2
2
 
3
3
  module CalculatingIndividual
4
4
 
5
+ def role_preparation
6
+ switch_on_the_calculator
7
+ end
8
+
5
9
  def switch_on_the_calculator
6
10
  @calculator = Calculator.new
7
11
  @operate_with = {
@@ -1,4 +1,4 @@
1
1
  in_order_to "Calculate", with_the_following: :calculation do
2
- see_how_to_do Calculations
2
+ see_how_to Calculations
3
3
  follow_the_steps_for the( :calculation ).split(" ")
4
4
  end
@@ -5,7 +5,6 @@ Feature: Subtraction
5
5
 
6
6
  Scenario Outline: Find the result of subtracting two numbers
7
7
  Given I am a Calculating Individual
8
- And I was able to switch on the calculator
9
8
  When I attempt to subtract, the number '<subtractor>' from the number '<subtractee>'
10
9
  Then I should see the answer '<result>'
11
10
 
@@ -5,7 +5,6 @@ Feature: Typical Calculator Workflow
5
5
 
6
6
  Scenario Outline: See what I expect based on specific interactions
7
7
  Given I am a calculating individual
8
- And I was able to switch on the calculator
9
8
  When I attempt to calculate: with the following '<interactions>'
10
9
  Then I should see the answer '<expected>'
11
10
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cukesalad (0.6.1)
4
+ cukesalad (0.7.0)
5
5
  aruba (>= 0.3.5)
6
6
  cucumber (>= 0.10.0)
7
7
  rspec (>= 2.5.0)
@@ -9,39 +9,59 @@ PATH
9
9
  GEM
10
10
  remote: http://rubygems.org/
11
11
  specs:
12
- aruba (0.3.6)
13
- childprocess (>= 0.1.7)
14
- cucumber (>= 0.10.0)
15
- rspec (>= 2.5.0)
12
+ archive-tar-minitar (0.5.2)
13
+ aruba (0.4.3)
14
+ bcat (>= 0.6.1)
15
+ childprocess (>= 0.1.9)
16
+ cucumber (>= 0.10.7)
17
+ rdiscount (>= 1.6.8)
18
+ rspec (>= 2.6.0)
19
+ bcat (0.6.1)
20
+ rack (~> 1.0)
16
21
  builder (3.0.0)
17
22
  childprocess (0.1.9)
18
23
  ffi (~> 1.0.6)
19
- cucumber (0.10.2)
24
+ cucumber (1.0.0)
20
25
  builder (>= 2.1.2)
21
26
  diff-lcs (>= 1.1.2)
22
- gherkin (>= 2.3.5)
27
+ gherkin (~> 2.4.1)
23
28
  json (>= 1.4.6)
24
29
  term-ansicolor (>= 1.0.5)
25
30
  diff-lcs (1.1.2)
26
- ffi (1.0.8)
27
- gherkin (2.3.8)
31
+ ffi (1.0.9)
32
+ ffi (1.0.9-java)
33
+ gherkin (2.4.1)
34
+ json (>= 1.4.6)
35
+ gherkin (2.4.1-java)
28
36
  json (>= 1.4.6)
29
- json (1.5.1)
37
+ json (1.4.6)
38
+ json (1.4.6-java)
39
+ mime-types (1.16)
40
+ rack (1.3.0)
30
41
  rake (0.8.7)
42
+ rdiscount (1.6.8)
43
+ relish (0.3.0)
44
+ archive-tar-minitar (~> 0.5.2)
45
+ json (~> 1.4.6)
46
+ rest-client (~> 1.6.1)
47
+ rest-client (1.6.3)
48
+ mime-types (>= 1.16)
31
49
  rspec (2.6.0)
32
50
  rspec-core (~> 2.6.0)
33
51
  rspec-expectations (~> 2.6.0)
34
52
  rspec-mocks (~> 2.6.0)
35
- rspec-core (2.6.0)
53
+ rspec-core (2.6.4)
36
54
  rspec-expectations (2.6.0)
37
55
  diff-lcs (~> 1.1.2)
38
56
  rspec-mocks (2.6.0)
39
57
  term-ansicolor (1.0.5)
40
58
 
41
59
  PLATFORMS
60
+ java
42
61
  ruby
43
62
 
44
63
  DEPENDENCIES
45
64
  bundler (~> 1.0.0)
46
65
  cukesalad!
47
66
  rake (~> 0.8.7)
67
+ relish (= 0.3.0)
data/Rakefile CHANGED
@@ -19,8 +19,11 @@ end
19
19
 
20
20
  require 'cucumber/rake/task'
21
21
  Cucumber::Rake::Task.new(:cucumber)
22
+ Cucumber::Rake::Task.new(:wip) do |wip|
23
+ wip.cucumber_opts = "-p wip"
24
+ end
22
25
 
23
- task :default => :spec
26
+ task :default => [:spec, :cucumber]
24
27
 
25
28
  require 'rake/rdoctask'
26
29
  Rake::RDocTask.new do |rdoc|
@@ -31,3 +34,20 @@ Rake::RDocTask.new do |rdoc|
31
34
  rdoc.rdoc_files.include('README*')
32
35
  rdoc.rdoc_files.include('lib/**/*.rb')
33
36
  end
37
+
38
+ require 'relish/command'
39
+ namespace :relish do
40
+ task :create do
41
+ `relish projects:add RiverGlide/CukeSalad`
42
+ end
43
+
44
+ task :push do
45
+ `relish push CukeSalad:#{CukeSalad::VERSION}`
46
+ end
47
+
48
+ namespace :version do
49
+ task :add do
50
+ `relish versions:add CukeSalad:#{CukeSalad::VERSION}`
51
+ end
52
+ end
53
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.7.0
data/cucumber.yml CHANGED
@@ -1,4 +1,6 @@
1
1
  default: --tags ~@wip --tags ~@todo
2
+ wip: --tags @wip
3
+ todo: --tags @todo
2
4
  all: features
3
5
  autotest: --color
4
6
  autotest-all: --color
data/cukesalad.gemspec CHANGED
@@ -10,7 +10,12 @@ Gem::Specification.new do |s|
10
10
  s.email = ["talktous@riverglide.com"]
11
11
  s.homepage = "https://github.com/RiverGlide/CukeSalad"
12
12
  s.summary = %q{Friction Free BDD/ATDD with cucumber}
13
- s.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.}
13
+ s.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.
14
+ New in this version:
15
+ - Single or double quotes can be used for parameters
16
+ - Single or double quotes can be used for expectations
17
+ - You can initialise the actor by having a role_preparation method in your role
18
+ }
14
19
 
15
20
  s.licenses = ["MIT"]
16
21
 
@@ -26,4 +31,5 @@ Gem::Specification.new do |s|
26
31
 
27
32
  s.add_development_dependency "bundler", "~> 1.0.0"
28
33
  s.add_development_dependency "rake", "~> 0.8.7"
34
+ s.add_development_dependency "relish", "= 0.3.0"
29
35
  end
@@ -0,0 +1,299 @@
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
+ You can see our current list of intended features under issues:
9
+ [https://github.com/RiverGlide/CukeSalad/issues?labels=Feature](https://github.com/RiverGlide/CukeSalad/issues?labels=Feature)
10
+
11
+
12
+ ## This project has step-free access!
13
+
14
+ 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.
15
+
16
+ With CukeSalad you don't need to write step-definitions.
17
+
18
+ Of course, you still have to write some code - but only the code that expresses:
19
+
20
+ * the roles and the actions they can perform
21
+ * the tasks and the actions involved in completing that task
22
+
23
+ ## Goals->Tasks->Actions
24
+ 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):
25
+
26
+ * *Goal:* What we’re trying to achieve which has one or more…
27
+ * *Tasks:* The high-level work-item that we complete to fulfil the goal, each having one or more…
28
+ * *Actions:* The specific steps or interactions we execute to complete the task.
29
+
30
+ More information about Goals, Tasks and Actions can be found in this [blog post](http://antonymarcano.com/blog/2011/03/goals-tasks-action/)
31
+
32
+ Let's see how this works with a simple example...
33
+
34
+ ## Install
35
+
36
+ gem install cukesalad
37
+
38
+ ## Let's Get started
39
+
40
+ Create a new project called Calculator:
41
+
42
+ cukesalad Calculator
43
+
44
+ Or, if you have an existing cucumber project that you want to configure to use cukesalad, you can type:
45
+
46
+ cukesalad
47
+
48
+ ## Write Features
49
+
50
+ In `features/`, let's create our first feature file - `a_place_to_start.feature`:
51
+
52
+ Feature: A Place To Start
53
+ As Callie, a calculating individual
54
+ I want to know when my calculator is on
55
+ So that I know when I can start calculating
56
+
57
+ Scenario: Let's Begin
58
+ Given I am a Calculating Individual
59
+ When I attempt to switch on the calculator
60
+ Then I should see the answer '0'
61
+
62
+ Let's take a moment to understand this scenario:
63
+
64
+ Scenario: Let's Begin
65
+ Given I am a <some role>
66
+ When I attempt to <do some task>
67
+ Then I should <ask some question> '<expected answer>'
68
+
69
+ To get this working, we don't need to write any steps. Instead, we describe tasks...
70
+
71
+ ## Create Tasks
72
+
73
+ Explaining how to do a _task_ is easy:
74
+ Create a new file, `features/lib/tasks/switch_on_the_calculator.rb`
75
+
76
+ Remember the step `When I attempt to switch on the calculator`
77
+
78
+ in_order_to "switch on the calculator" do
79
+ switch_on_the_calculator
80
+ end
81
+
82
+ Remember the step `Then I should see the answer '0'`
83
+ Now we need `task/see_the_answer.rb`
84
+
85
+ in_order_to "see the answer" do
86
+ look_at_the_display
87
+ end
88
+
89
+ Now we've explained the _tasks_, we need to define the _role_ that performs them. In
90
+ this example, we need to explain how the `CalculatingIndividual` _role_ works...
91
+
92
+ ## Create Roles
93
+
94
+ Remember the step `Given I am a Calculating Individual`?
95
+
96
+ We explain a _role_ by creating a new file
97
+ called `features/lib/roles/calculating_individual.rb`
98
+
99
+ module CalculatingIndividual
100
+
101
+ def switch_on_the_calculator
102
+ @calculator = Calculator.new
103
+ end
104
+
105
+ def look_at_the_display
106
+ @calculator.display
107
+ end
108
+ end
109
+
110
+ You'll need a class called Calculator on the load path of course, but that's it.
111
+
112
+ From your project folder, run (_note: '%' is our command prompt_)
113
+
114
+ % cucumber
115
+
116
+ We now have our first passing Feature, without creating a single step definition!
117
+
118
+ ## Wash, rinse, repeat
119
+
120
+ Let's try another scenario...
121
+
122
+ Scenario Outline: Find the sum of two numbers
123
+ Given I am a Calculating Individual
124
+ And I was able to switch on the calculator
125
+ When I attempt to add: the number '10' and the number '10'
126
+ Then I should see the answer '20'
127
+
128
+ Notice that we've reused 'switch on the calculator'.
129
+
130
+ The new _When_ step has a slightly different layout.
131
+ Let's examine that for a second... See below. Notice the ':' (colon) after `<do something>` followed by the name-value pairs:
132
+
133
+ When I attempt to <do something>: <name> '<value>' <name> '<value>'
134
+
135
+ You can also use a ',' (comma) in situations where a colon wouldn't quite work:
136
+
137
+ When I attempt to <do something>, <name> '<value>' <name> '<value>'
138
+
139
+ `<do something>` can be as many words as you like. You can have as many name-value pairs as you like.
140
+
141
+ For this to work we need a task called `tasks/add.rb` that explains the individual actions required to complete the task:
142
+
143
+ in_order_to "add" do
144
+ enter @value_of(:the_number)
145
+ press :plus
146
+ enter @value_of(:and_the_number)
147
+ press :equals
148
+ end
149
+
150
+ Notice how the `value_of` lines use symbols that correspond to the wording `'the number '10' to the number '10'` in the "When" step.
151
+
152
+ There is some 'syntactic sugar' that we can use to dress this up a little and make it read nicer... a simple attribute mapping (using Ruby 1.9.x syntax):
153
+
154
+ in_order_to "add", the_number: :first_number, to_the_number: :second_number do
155
+ enter the :first_number
156
+ press :plus
157
+ enter the :second_number
158
+ press :equals
159
+ end
160
+
161
+ All we've done is mapped `:the_number` to `:first_number` and `:to_the_number` to `:second_number`. There is a special method called "the" that allows you to reference the mapped values rather than the symbols derived from the scenario.
162
+
163
+ Now all we need to do is create the corresponding methods in `calculating_individual.rb`.
164
+
165
+ module CalculatingIndividual
166
+
167
+ def switch_on_the_calculator
168
+ @calculator = Calculator.new
169
+ @operate_with = {
170
+ plus: :+,
171
+ minus: :-
172
+ }
173
+ end
174
+
175
+ def enter value
176
+ @calculator.enter value.to_i
177
+ end
178
+
179
+ def press next_operator
180
+ if next_operator == :equals
181
+ equals
182
+ else
183
+ @calculator.get_ready_to @operate_with[next_operator]
184
+ end
185
+ end
186
+
187
+ def equals
188
+ @calculator.equals
189
+ end
190
+
191
+ def look_at_the_display
192
+ @calculator.display
193
+ end
194
+ end
195
+
196
+ Of course you'll have to [implement the calculator too](https://github.com/RiverGlide/CukeSalad/blob/master/Examples/Calculator/lib/calculator.rb)
197
+
198
+ Now, you can run cucumber again:
199
+
200
+ % cucumber
201
+
202
+ There's no need to write `step_definitions`...
203
+ Simply express the _roles_ and the _tasks_ in clear,
204
+ concise, easy to read classes.
205
+
206
+ If we want to know what things we can say, instead of trawling through a step-def ruby file, we can look in our tasks folder:
207
+
208
+ features/lib/default/tasks/
209
+ ├── add.rb
210
+ ├── calculate.rb
211
+ ├── calculations.rb
212
+ ├── see_the_answer.rb
213
+ ├── subtract.rb
214
+ └── switch_on_the_calculator.rb
215
+
216
+ You can structure your tasks as you see fit. For example, as the project grows, it might end up looking like this:
217
+
218
+ features/lib/default/tasks/
219
+ ├── all_purpose
220
+ | └── calculate.rb
221
+ ├── arithmetic
222
+ | ├── add.rb
223
+ | ├── divide.rb
224
+ | ├── multiply.rb
225
+ | └── subtract.rb
226
+ ├── extras
227
+ | ├── recall_from_memory.rb
228
+ | ├── store_in_memory.rb
229
+ | └── switch_on_the_calculator.rb
230
+ ├── questions
231
+ | ├── see_the_answer.rb
232
+ | ├── see_the_following_indicators.rb
233
+ | └── switch_on_the_calculator.rb
234
+ ├── trigonometry
235
+ | ├── sine.rb
236
+ | ├── cosine.rb
237
+ | └── tangent.rb
238
+ └── reference_material
239
+ └── calculations.rb
240
+
241
+ ## Alternative Roles
242
+
243
+ As our features _describe the value of a calculator application and not its
244
+ implementation_, we have the opportunity to reuse them.
245
+
246
+ In the Calculator example, we create a new _role_ in
247
+ `./features/lib/alternative/roles/calculating_web_user.rb`, which we can swap
248
+ into our tests using a Cucumber profile defined in `features/cucumber.yml`:
249
+
250
+ default --exclude features/lib/alternative/
251
+ alternative -r features/lib/alternative/ -r features/support/env.rb -r features/lib/default/tasks/
252
+
253
+ We can run our alternative configuration like so:
254
+
255
+ `%cucumber --profile alternative`
256
+
257
+ The Calculating Web User masquerades as the Calculating Individual from our
258
+ previous example, and provides the same API, allowing us to reuse all of our
259
+ existing features and _tasks_.
260
+
261
+ The alternative, `./lib/web_calculator.rb`, implementation is a simple [Sinatra](http://www.sinatrarb.com) application,
262
+ which we drive with the [Capybara](http://github.com/jnicklas/capybara) web testing framework.
263
+
264
+ By writing a single new _role_ class we're able to reuse all of our existing features,
265
+ _tasks_ and even the `Calculator` itself, which the web calculator delegates to in order to do its calculations.
266
+
267
+ After adding some more scenarios and tasks and an alternative "Calculating Individual" (see below for why), our Calculator directory structure currently looks like this...
268
+
269
+ ├── cucumber.yml
270
+ ├── features
271
+ │   ├── A_PlaceToStart.feature
272
+ │   ├── Addition.feature
273
+ │   ├── Complex_calculations.feature
274
+ │   ├── Subtraction.feature
275
+ │   ├── Typical_workflow.feature
276
+ │   ├── lib
277
+ │   │   ├── alternative
278
+ │   │   │   ├── roles
279
+ │   │   │   │   └── calculating_web_user.rb
280
+ │   │   │   └── tasks
281
+ │   │   └── default
282
+ │   │   ├── roles
283
+ │   │   │   └── calculating_individual.rb
284
+ │   │   └── tasks
285
+ │   │   ├── add.rb
286
+ │   │   ├── perform.rb
287
+ │   │   ├── see_the_answer.rb
288
+ │   │   ├── subtract.rb
289
+ │   │   └── switch_on_the_calculator.rb
290
+ │   └── support
291
+ │   └── env.rb
292
+ ├── lib
293
+ │   ├── calculator.rb
294
+ │   └── web_calculator.rb
295
+ └── spec
296
+ ├── calculator_spec.rb
297
+ └── web_calculator_spec.rb
298
+
299
+ 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.
@@ -1,4 +1,4 @@
1
- Feature: Cuke Salad
1
+ Feature: Creating a New Project
2
2
  As a Step Free Cuker
3
3
  You want to set up your project to use use Cuke Salad
4
4
  So that you can start writing scenarios without step definitions
@@ -5,7 +5,6 @@ Feature: Define the Role
5
5
 
6
6
  Background:
7
7
  Given you are a Step Free Cuker
8
- And you were able to create a new Cuke Salad project
9
8
 
10
9
  Scenario: We'll tell you what you need to do to establish the role
11
10
  Given you did not create a role: called 'NewCustomer'
@@ -6,11 +6,10 @@ Feature: Define the Task
6
6
 
7
7
  Background:
8
8
  Given you are a Step Free Cuker
9
- And you were able to create a new Cuke Salad project
10
9
  And you were able to create a role: called 'NewCustomer'
11
10
 
12
11
  Scenario Outline: Once you've created the task, you see the step pass
13
- Given you did create a task: called 'do something'
12
+ Given you were able to create a task: called 'do something'
14
13
  When you attempt to run a scenario: containing
15
14
  """
16
15
  Given I am a New Customer
@@ -6,25 +6,33 @@ Feature: Define a Task with arguments
6
6
 
7
7
  Background:
8
8
  Given you are a Step Free Cuker
9
- And you were able to create a new Cuke Salad project
10
9
  And you were able to create a role: called 'NewCustomer'
11
- And you were able to create a task: called 'do something'
12
10
 
13
11
  Scenario Outline: A task can accept arguments
12
+ Given you were able to create a task, called 'do some task' containing
13
+ """
14
+ in_order_to 'do some task', with: :detail do
15
+ raise "Expected 'information' in the detail
16
+ got '#{the :detail}'" unless the( :detail ) == 'information'
17
+ end
18
+ """
14
19
  When you attempt to run a scenario: called 'something' containing
15
20
  """
16
21
  Given I am a New Customer
17
- <the_step>
22
+ When I attempt to <task_with_argument>
18
23
  """
19
24
  Then you should see it has 'passed'
20
25
 
21
26
  Examples:
22
- | the_step |
23
- | When I attempt to do something: with 'information' |
24
- | When I attempt to do something, with 'information' |
27
+ | task_with_argument |
28
+ | do some task: with 'information' |
29
+ | do some task, with 'information' |
30
+ | do some task: with "information" |
31
+ | do some task, with "information" |
25
32
 
26
33
  Scenario: A task accepts tables
27
- When you attempt to run a scenario, called 'something' containing
34
+ Given you were able to create a task: called 'do something'
35
+ When you attempt to run a scenario, called 'something' containing
28
36
  """
29
37
  Given I am a New Customer
30
38
  When I attempt to do something, with
@@ -0,0 +1,39 @@
1
+ Feature: Expressing expectations
2
+ As a Step Free Cuker
3
+ You want to express expectations
4
+ So that you know whether your scenario has passed
5
+
6
+ Background:
7
+ Given you are a Step Free Cuker
8
+ And you were able to create a file, at 'features/roles/role_with_answers.rb' containing
9
+ """
10
+ module RoleWithAnswers
11
+ def see_the_answer
12
+ get_the_answer_from_the_application
13
+ end
14
+
15
+ def get_the_answer_from_the_application
16
+ # Pretending to get the answer from the application
17
+ return 'correct answer'
18
+ end
19
+ end
20
+ """
21
+ And you were able to create a task, called 'see the answer is' containing
22
+ """
23
+ in_order_to 'see the answer is' do
24
+ see_the_answer
25
+ end
26
+ """
27
+
28
+ Scenario Outline: Simple Expectation
29
+ When you attempt to run a scenario, containing
30
+ """
31
+ Given I am a Role With Answers
32
+ Then I should see the answer is <answer>
33
+ """
34
+ Then you should see it has 'passed'
35
+
36
+ Examples:
37
+ | answer |
38
+ | 'correct answer' |
39
+ | "correct answer" |
@@ -2,4 +2,19 @@ require 'aruba/api'
2
2
  #TODO: Consider wrapping Aruba
3
3
  module StepFreeCuker
4
4
  include Aruba::Api
5
+
6
+ def role_preparation
7
+ create_a_new_cuke_salad_project
8
+ end
9
+
10
+ def create_a_new_cuke_salad_project
11
+ create_dir 'features'
12
+ create_dir 'features/support'
13
+ write_file 'features/support/env.rb', "$:.unshift(File.dirname(__FILE__) + '/../../../../lib') #where to find CukeSalad
14
+
15
+ require 'cukesalad'"
16
+ create_dir 'features/lib'
17
+ create_dir 'features/lib/roles'
18
+ create_dir 'features/lib/tasks'
19
+ end
5
20
  end
@@ -1,11 +1,3 @@
1
- #TOOO: consider doing this as a feature since it's part of how you set up the project.
2
- in_order_to "CreateANewCukeSaladProject" do
3
- create_dir 'features'
4
- create_dir 'features/support'
5
- write_file 'features/support/env.rb', "$:.unshift(File.dirname(__FILE__) + '/../../../../lib') #where to find CukeSalad
6
-
7
- require 'cukesalad'"
8
- create_dir 'features/lib'
9
- create_dir 'features/lib/roles'
10
- create_dir 'features/lib/tasks'
1
+ in_order_to 'create a new cukesalad project' do
2
+ create_a_new_cuke_salad_project
11
3
  end
@@ -1,12 +1,12 @@
1
1
  in_order_to 'create a task', called: :name_of_task, containing: :code do
2
- file_name = the( :name_of_task ).gsub(" ", "_")
3
-
4
- default_content =
5
- "in_order_to '#{the :name_of_task}' do
6
- #nothing
7
- end"
8
- content = the :code
9
- content = default_content if content.nil?
2
+ file_name = the( :name_of_task ).gsub(" ", "_")
3
+
4
+ default_content =
5
+ "in_order_to '#{the :name_of_task}' do
6
+ #nothing
7
+ end"
8
+ content = the :code
9
+ content = default_content if content.nil?
10
10
 
11
- write_file "features/lib/tasks/#{file_name}.rb", content
11
+ write_file "features/lib/tasks/#{file_name}.rb", content
12
12
  end
@@ -0,0 +1,36 @@
1
+ Feature: Prepare the actor for the role
2
+ As a Step Free Cuker
3
+ You want the role to initialize some things
4
+ So that you can define the things that the role always does at the start
5
+
6
+ Scenario: Initialization
7
+ Given you are a Step Free Cuker
8
+ And you were able to create a file, at 'features/roles/role_with_prep.rb' containing
9
+ """
10
+ module RoleWithPrep
11
+ def role_preparation
12
+ do_something_important
13
+ end
14
+
15
+ def do_something_important
16
+ @something = 'something important was done'
17
+ end
18
+
19
+ def see_what_was_done
20
+ @something
21
+ end
22
+ end
23
+ """
24
+ And you were able to create a task, called 'see that' containing
25
+ """
26
+ in_order_to 'see that' do
27
+ see_what_was_done
28
+ end
29
+ """
30
+ When you attempt to run a scenario, containing
31
+ """
32
+ Given I am a Role With Prep
33
+ Then I should see that 'something important was done'
34
+ """
35
+ Then you should see it has 'passed'
36
+
@@ -5,7 +5,6 @@ Feature: Remember information between steps
5
5
 
6
6
  Background:
7
7
  Given you are a Step Free Cuker
8
- And you were able to create a new Cuke Salad project
9
8
  And you were able to create a role, called 'NewCustomer'
10
9
 
11
10
  Scenario: You can reuse information
data/lib/cukesalad.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  require 'cukesalad/salad'
2
- require 'cukesalad/cucumber'
2
+ require 'cukesalad/cucumber_steps'
@@ -5,8 +5,8 @@ module CukeSalad
5
5
 
6
6
  def initialize this_type_of_role, directed_by=Director.new
7
7
  @director = directed_by
8
- get_into_character_for this_type_of_role
9
8
  @note_pad = {}
9
+ get_into_character_for this_type_of_role
10
10
  end
11
11
 
12
12
  def perform described_task, details = {}
@@ -19,6 +19,7 @@ module CukeSalad
19
19
  def get_into_character_for described_role
20
20
  the_role = @director.explain_the_role described_role
21
21
  see_how_to_do the_role
22
+ role_preparation
22
23
  end
23
24
 
24
25
  def get_ready_to_perform something
@@ -29,6 +30,11 @@ module CukeSalad
29
30
  def see_how_to_do something
30
31
  extend something
31
32
  end
33
+ alias :see_how_to :see_how_to_do
34
+
35
+ def role_preparation
36
+ # Does nothing unless you override it from your role
37
+ end
32
38
 
33
39
  def value_of(symbol)
34
40
  @info[symbol]
@@ -26,7 +26,11 @@ Then /^(?:I|you) should ([^':]*)(?: '([^']*)')$/ do | this_question, expect_valu
26
26
  @actor.answer( this_question ).to_s.should == expect_value
27
27
  end
28
28
 
29
- Then /^(?:I|you) should ([^':]+)$/ do | this_question |
29
+ Then /^(?:I|you) should ([^':]*)(?: "([^"]*)")$/ do | this_question, expect_value |
30
+ @actor.answer( this_question ).to_s.should == expect_value
31
+ end
32
+
33
+ Then /^(?:I|you) should ([^'^":]+)$/ do | this_question |
30
34
  @actor.answer( this_question )
31
35
  end
32
36
 
@@ -10,7 +10,7 @@ module CukeSalad
10
10
  begin
11
11
  find_directives_for name
12
12
  rescue NameError
13
- raise "I can't find a role called '#{ name }'. Have you created it?\ne.g.\n module #{ name }\n end"
13
+ raise "I can't find a role called '#{ name }'. Have you created it?\ne.g.\n module #{ name }\n end\n\n"
14
14
  end
15
15
  end
16
16
 
@@ -19,7 +19,7 @@ module CukeSalad
19
19
  begin
20
20
  find_directives_for name
21
21
  rescue NameError
22
- raise "I can't find a task called '#{ something }'. Have you created it?\ne.g.\n in_order_to '#{ something }' do\n # the actions\n end"
22
+ raise "I can't find a task called '#{ something }'. Have you created it?\ne.g.\n in_order_to '#{ something }' do\n # the actions\n end\n\n"
23
23
  end
24
24
  end
25
25
 
@@ -21,7 +21,7 @@ module CukeSalad
21
21
  end
22
22
 
23
23
  def names_and_values_in details
24
- specifics_pattern = /('[^']+')/
24
+ specifics_pattern = /('[^']+'|"[^"]+")/
25
25
  details.split(specifics_pattern)
26
26
  end
27
27
 
@@ -30,7 +30,7 @@ module CukeSalad
30
30
  end
31
31
 
32
32
  def the_value_from_the item
33
- item.gsub(/(^'|'$)/, '') unless item.nil?
33
+ item.gsub(/((?:^'|'$)|(?:^"|"$))/, '') unless item.nil?
34
34
  end
35
35
  end
36
36
  end
@@ -1,3 +1,3 @@
1
1
  module CukeSalad
2
- VERSION = "0.6.1"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -7,31 +7,38 @@ end
7
7
  module CukeSalad
8
8
  describe Specifics do
9
9
 
10
- it "has an item of specific information" do
11
- something = NeedingSpecifics.new
12
- something.understand_the "specific 'information'"
13
- something.value_of(:specific).should == "information"
14
- end
10
+ context 'name value pairs' do
15
11
 
16
- it "has items of specific information" do
17
- something = NeedingSpecifics.new
18
- something.understand_the "first 'item' second 'another'"
19
- something.value_of(:first).should == "item"
20
- something.value_of(:second).should == "another"
21
- end
12
+ [ "specific 'information'",
13
+ 'specific "information"'
14
+ ].each do | specifics |
15
+ it "can be found in: #{specifics}" do
16
+ something = NeedingSpecifics.new
17
+ something.understand_the specifics
18
+ something.value_of(:specific).should == "information"
19
+ end
20
+ end
21
+
22
+ it "can have more than one name-value pair" do
23
+ something = NeedingSpecifics.new
24
+ something.understand_the "first 'item' second 'another'"
25
+ something.value_of(:first).should == "item"
26
+ something.value_of(:second).should == "another"
27
+ end
22
28
 
23
- it "copes with names having more than one word" do
24
- something = NeedingSpecifics.new
25
- something.understand_the "first thing 'item' second thing 'another'"
26
- something.value_of(:first_thing).should == "item"
27
- something.value_of(:second_thing).should == "another"
28
- end
29
-
30
- it "should cope with values having more than one word" do
31
- something = NeedingSpecifics.new
32
- something.understand_the "first thing 'item' second thing 'another thing'"
33
- something.value_of(:first_thing).should == "item"
34
- something.value_of(:second_thing).should == "another thing"
29
+ it "can have more than one word as the name" do
30
+ something = NeedingSpecifics.new
31
+ something.understand_the "first thing 'item' second thing 'another'"
32
+ something.value_of(:first_thing).should == "item"
33
+ something.value_of(:second_thing).should == "another"
34
+ end
35
+
36
+ it "can have more than one word as the name or value" do
37
+ something = NeedingSpecifics.new
38
+ something.understand_the "first thing 'item' second thing 'another thing'"
39
+ something.value_of(:first_thing).should == "item"
40
+ something.value_of(:second_thing).should == "another thing"
41
+ end
35
42
  end
36
43
 
37
44
  context 'the last item' do
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: cukesalad
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.6.1
5
+ version: 0.7.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - RiverGlide
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-19 00:00:00 +01:00
13
+ date: 2011-07-03 00:00:00 +01:00
14
14
  default_executable: cukesalad
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -68,7 +68,18 @@ dependencies:
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: *id005
71
- description: 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.
71
+ - !ruby/object:Gem::Dependency
72
+ name: relish
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - "="
77
+ - !ruby/object:Gem::Version
78
+ version: 0.3.0
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: *id006
82
+ description: "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.\n New in this version:\n - Single or double quotes can be used for parameters\n - Single or double quotes can be used for expectations\n - You can initialise the actor by having a role_preparation method in your role\n "
72
83
  email:
73
84
  - talktous@riverglide.com
74
85
  executables:
@@ -82,6 +93,7 @@ files:
82
93
  - .rspec
83
94
  - Examples/Calculator/Gemfile
84
95
  - Examples/Calculator/Gemfile.lock
96
+ - Examples/Calculator/README.md
85
97
  - Examples/Calculator/cucumber.yml
86
98
  - Examples/Calculator/features/LOOK_MA_NO_STEP_DEFS.txt
87
99
  - Examples/Calculator/features/a_place_to_start.feature
@@ -112,10 +124,12 @@ files:
112
124
  - bin/cukesalad
113
125
  - cucumber.yml
114
126
  - cukesalad.gemspec
115
- - features/a_new_cukesalad_project.feature
127
+ - features/README.markdown
128
+ - features/creating_a_new_project.feature
116
129
  - features/define_a_role.feature
117
130
  - features/define_a_task.feature
118
131
  - features/define_a_task_with_arguments.feature
132
+ - features/expressing_expectations.feature
119
133
  - features/lib/roles/step_free_cuker.rb
120
134
  - features/lib/tasks/create_a_file.rb
121
135
  - features/lib/tasks/create_a_new_cukesalad_project.rb
@@ -129,13 +143,14 @@ files:
129
143
  - features/lib/tasks/run_a_scenario.rb
130
144
  - features/lib/tasks/see_a_reply.rb
131
145
  - features/lib/tasks/see_the_step_has.rb
146
+ - features/prepare_the_actor_for_the_role.feature
132
147
  - features/remember_information_between_steps.feature
133
148
  - features/support/env.rb
134
149
  - lib/cukesalad.rb
135
150
  - lib/cukesalad/actor.rb
136
151
  - lib/cukesalad/cli.rb
137
152
  - lib/cukesalad/codify/const_name.rb
138
- - lib/cukesalad/cucumber.rb
153
+ - lib/cukesalad/cucumber_steps.rb
139
154
  - lib/cukesalad/director.rb
140
155
  - lib/cukesalad/salad.rb
141
156
  - lib/cukesalad/specifics.rb
@@ -162,7 +177,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
162
177
  requirements:
163
178
  - - ">="
164
179
  - !ruby/object:Gem::Version
165
- hash: -3357820802428433430
180
+ hash: 3570330056691710889
166
181
  segments:
167
182
  - 0
168
183
  version: "0"
@@ -171,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
186
  requirements:
172
187
  - - ">="
173
188
  - !ruby/object:Gem::Version
174
- hash: -3357820802428433430
189
+ hash: 3570330056691710889
175
190
  segments:
176
191
  - 0
177
192
  version: "0"
@@ -183,10 +198,12 @@ signing_key:
183
198
  specification_version: 3
184
199
  summary: Friction Free BDD/ATDD with cucumber
185
200
  test_files:
186
- - features/a_new_cukesalad_project.feature
201
+ - features/README.markdown
202
+ - features/creating_a_new_project.feature
187
203
  - features/define_a_role.feature
188
204
  - features/define_a_task.feature
189
205
  - features/define_a_task_with_arguments.feature
206
+ - features/expressing_expectations.feature
190
207
  - features/lib/roles/step_free_cuker.rb
191
208
  - features/lib/tasks/create_a_file.rb
192
209
  - features/lib/tasks/create_a_new_cukesalad_project.rb
@@ -200,6 +217,7 @@ test_files:
200
217
  - features/lib/tasks/run_a_scenario.rb
201
218
  - features/lib/tasks/see_a_reply.rb
202
219
  - features/lib/tasks/see_the_step_has.rb
220
+ - features/prepare_the_actor_for_the_role.feature
203
221
  - features/remember_information_between_steps.feature
204
222
  - features/support/env.rb
205
223
  - spec/cukesalad/actor_spec.rb