macros4cuke 0.5.03 → 0.5.06

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.
Files changed (36) hide show
  1. checksums.yaml +8 -8
  2. data/.rubocop.yml +8 -5
  3. data/.travis.yml +0 -1
  4. data/CHANGELOG.md +14 -0
  5. data/Gemfile +4 -4
  6. data/Rakefile +19 -13
  7. data/features/step_definitions/demo_steps.rb +10 -6
  8. data/features/support/my_formatter.rb +25 -0
  9. data/lib/macro_steps.rb +1 -1
  10. data/lib/macros4cuke/application.rb +7 -5
  11. data/lib/macros4cuke/cli/cmd-line.rb +1 -1
  12. data/lib/macros4cuke/coll-walker-factory.rb +1 -1
  13. data/lib/macros4cuke/constants.rb +3 -3
  14. data/lib/macros4cuke/formatter/all-notifications.rb +1 -1
  15. data/lib/macros4cuke/formatter/to-gherkin.rb +4 -4
  16. data/lib/macros4cuke/formatter/to-null.rb +14 -14
  17. data/lib/macros4cuke/formatter/to-trace.rb +9 -9
  18. data/lib/macros4cuke/formatting-service.rb +9 -9
  19. data/lib/macros4cuke/macro-step.rb +6 -7
  20. data/lib/macros4cuke/templating/comment.rb +1 -1
  21. data/lib/macros4cuke/templating/engine.rb +8 -75
  22. data/lib/macros4cuke/templating/eo-line.rb +1 -1
  23. data/lib/macros4cuke/templating/section.rb +2 -2
  24. data/lib/macros4cuke/templating/static-text.rb +1 -1
  25. data/spec/macros4cuke/application_spec.rb +3 -3
  26. data/spec/macros4cuke/cli/cmd-line_spec.rb +1 -1
  27. data/spec/macros4cuke/coll-walker-factory_spec.rb +4 -4
  28. data/spec/macros4cuke/formatter/to-gherkin_spec.rb +1 -1
  29. data/spec/macros4cuke/formatter/to-null_spec.rb +1 -1
  30. data/spec/macros4cuke/formatter/to-trace_spec.rb +1 -1
  31. data/spec/macros4cuke/formatting-service_spec.rb +17 -17
  32. data/spec/macros4cuke/macro-collection_spec.rb +1 -1
  33. data/spec/macros4cuke/macro-step_spec.rb +3 -3
  34. data/spec/macros4cuke/templating/engine_spec.rb +15 -15
  35. data/spec/macros4cuke/templating/section_spec.rb +1 -1
  36. metadata +5 -4
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OTA1NWJhMjkxZGJhMjA3MTExOTNkOTEyYmYzNWNhYjJkYjkxYTllNA==
4
+ YTZhNThhYzQ3YzBlZjI4NjQwOGZkYzRlMTVkZTk4ODFjZTEzZjE1OQ==
5
5
  data.tar.gz: !binary |-
6
- ODRlMTdiNDAyM2JhMTUwNmU0ZjVmZjcwOTBhYjY3MDA0NDhkMzQwNg==
6
+ ZDZjNzBjOGVjZGJlNTc3YjY3ZmYwMTI1OTkzYTk4MzRiOWQ2ODA5Ng==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ODAzYWYyNWYzNGFlOTA2N2NmYzBlYmZkZWIwZWE2NTI2M2YyMmJiNjA2MzQx
10
- NzhlMGVhNDg4NzBjOGE3YThkYTRhMTExNjZlNzZlMzA2Y2IxODQ0ZGY5MTIy
11
- ZjBiNjhkMWVhYzAxNjU0MGRkNGFiMGMwYWMwNmEwY2IzZTExOTY=
9
+ MTFhZTcxYzVjOGJiMzlkODcyYzM0ZDk0YzEyYzQ5OWU4MjdkMzRiNjRlMWMx
10
+ OGYyZDhlMmMxNDY2ZjZkNzNhYTJlMWI2N2EyZGU2Y2E1ZmQ4ZDhjNDVmMjhk
11
+ OWUzZTJhYjY1NGFiMWY4YjRlZTk5MjExYzllZTMyZTBlMmEzMjY=
12
12
  data.tar.gz: !binary |-
13
- ZTY1MTE5MzM3OTQ1MmIyMzg5ZjU4ZTJmYzM5ODM3YzU1MmRkZTRkZGZlNWUy
14
- ZjczOGExNTA3NDg3MzY2NWJlYzMxNjE4ZGRiYzY3ZmU2YzA4OGE1OWNjZTA3
15
- ZDBkOGI5Y2YwZjZmZmY3MTExMTY2YTdjMjNjYTU2ODBlMWMxMGY=
13
+ MzNhYTViYTA2MDRkMWZkZjExYTk3Y2RlN2Q1Y2YwMGUzMWU4MWEwZDdkOWNm
14
+ OTE3NzQ0Y2M2NzY3ZmE3ZmNmNzk0N2I1NTA3NWE5OTU1NmEwODBhYTM0ZTdh
15
+ NWEyN2M1NjNiZWZhZGE5NDZhMzY0MGFmNzI1ODRlOTQ4YTlhZTE=
data/.rubocop.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  AllCops:
2
- Excludes:
3
- - '*/examples/**'
4
- - '*/features/**'
5
- - '*/gems/**'
2
+ Exclude:
3
+ - 'examples/**/*'
4
+ - 'features/**/*'
5
+ - 'gems/**/*'
6
6
 
7
7
  # This is disabled because some demos use UTF-8
8
8
  AsciiComments:
@@ -47,7 +47,10 @@ IndentationWidth :
47
47
  # Avoid methods longer than 50 lines of code
48
48
  MethodLength:
49
49
  Max: 50
50
- CountComments: false
50
+ CountComments: false
51
+
52
+ NonNilCheck:
53
+ Enabled: false
51
54
 
52
55
  NumericLiterals:
53
56
  Enabled: false
data/.travis.yml CHANGED
@@ -6,7 +6,6 @@ rvm:
6
6
  - 1.9.2
7
7
  - jruby-19mode
8
8
  - jruby-head
9
- - rbx
10
9
 
11
10
  # Workaround issue of jruby-head configuration on Travis CI
12
11
  matrix:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ### 0.5.06 / 2014-06-30
2
+ * [CHANGE] Spec files upgraded to RSpec3.x.x
3
+ * [CHANGE] File `Gemfile` updated with dependency on RSpec3
4
+ * [CHANGE] File `macros4cuke.gemspec` updated with dependency on RSpec3
5
+
6
+
7
+ ### 0.5.05 / 2014-06-30
8
+ * [CHANGE] Many files updated for Rubocop 0.24.0. There remain 4 Rubocop offenses.
9
+
10
+
11
+ ### 0.5.04 / 2014-04-07
12
+ * [CHANGE] File `.rubocop.yml`: Updated for Rubocop 0.20.1. NonNilCheck cop disabled.
13
+
14
+
1
15
  ### 0.5.03 / 2014-04-01
2
16
  * [CHANGE] File `README.md`: Updated the installation steps.
3
17
  * [CHANGE] Files `macro_support.rb` renamed to `use_macros4cuke.rb`
data/Gemfile CHANGED
@@ -1,10 +1,10 @@
1
1
  source 'https://rubygems.org'
2
2
  # Prevent Bundler to load the dependencies from our .gemspec file
3
3
 
4
- gem "cucumber", [">= 0.5.0"]
4
+ gem 'cucumber', [">= 0.5.0"]
5
5
 
6
6
  group :development do
7
- gem "rake", ">= 0.8.0"
8
- gem "rspec", ">= 2.11.0"
9
- gem "simplecov", ">= 0.5.0"
7
+ gem 'rake', '>= 0.8.0'
8
+ gem 'rspec', '>= 3.0.0'
9
+ gem 'simplecov', '>= 0.5.0'
10
10
  end
data/Rakefile CHANGED
@@ -17,18 +17,24 @@ require 'cucumber/rake/task'
17
17
  # UGLY workaround for bug in Cucumber's rake task
18
18
  if Gem::VERSION[0].to_i >= 2 && Cucumber::VERSION <= '1.3.2'
19
19
  # Monkey-patch a buggy method
20
- class Cucumber::Rake::Task::ForkedCucumberRunner
21
- def gem_available?(gemname)
22
- if Gem::VERSION[0].to_i >= 2
23
- gem_available_new_rubygems?(gemname)
24
- else
25
- gem_available_old_rubygems?(gemname)
26
- end
27
- end
28
- end # class
20
+ module Cucumber
21
+ module Rake
22
+ class Task
23
+ class ForkedCucumberRunner
24
+ def gem_available?(gemname)
25
+ if Gem::VERSION[0].to_i >= 2
26
+ gem_available_new_rubygems?(gemname)
27
+ else
28
+ gem_available_old_rubygems?(gemname)
29
+ end
30
+ end
31
+ end # class
32
+ end # class
33
+ end # module
34
+ end # module
29
35
  end
30
36
 
31
- Cucumber::Rake::Task.new do |t|
37
+ Cucumber::Rake::Task.new do |_|
32
38
  end
33
39
 
34
40
  # RSpec as testing tool
@@ -41,10 +47,10 @@ end
41
47
 
42
48
  # Combine RSpec and Cucumber tests
43
49
  desc 'Run tests, with RSpec and Cucumber'
44
- task :test => [:spec, :cucumber]
50
+ task test: [:spec, :cucumber]
45
51
 
46
52
 
47
53
  # Default rake task
48
- task :default => :test
54
+ task default: :test
49
55
 
50
- # End of file
56
+ # End of file
@@ -2,22 +2,26 @@
2
2
  # A few step definitions for demo and testing purpose.
3
3
 
4
4
  When(/^I landed in the homepage$/) do
5
- #trace_steps << 'Invoked step: ... I landed in the homepage'
5
+ # trace_steps << 'Invoked step: ... I landed in the homepage'
6
6
  end
7
7
 
8
8
  When(/^I click "([^"]*)"$/) do |element|
9
- #trace_steps << "Invoked step: ... I click \"#{element}\""
9
+ msg = 'Invoked step: ... I click '
10
+ msg << "\"#{element}\""
11
+ # trace_steps << msg
10
12
  end
11
13
 
12
14
 
13
15
  When(/^I fill in "(.*?)" with "(.*?)"$/) do |element, text|
14
- #trace_steps << "Invoked step: ... I fill in \"#{element}\" with \"#{text}\""
16
+ msg = "Invoked step: ... I fill in \"#{element}\" with "
17
+ msg << "\"#{text}\""
18
+ # trace_steps << msg
15
19
  end
16
20
 
17
21
 
18
22
  Then(/^I expect the following step trace:$/) do |step_text|
19
- #trace_steps.should == step_text.split(/\r?\n|\n/)
20
- substeps_trace.chomp.should == step_text
23
+ # trace_steps.should == step_text.split(/\r?\n|\n/)
24
+ expect(substeps_trace.chomp).to eq(step_text)
21
25
  end
22
26
 
23
27
 
@@ -34,7 +38,7 @@ SNIPPET
34
38
  rescue Macros4Cuke::DataTableNotFound => exc
35
39
  phrase = '[fill in the form with]:'
36
40
  msg = "The step with phrase #{phrase} requires a data table."
37
- exc.message.should == msg
41
+ expect(exc.message).to eq(msg)
38
42
  end
39
43
  end
40
44
 
@@ -0,0 +1,25 @@
1
+ module Macros4Cuke # Module used as a namespace
2
+
3
+ require 'pp'
4
+
5
+ class MyFormatter
6
+ attr_reader(:ostream)
7
+
8
+ def initialize(_, io, _)
9
+ @ostream = io
10
+ end
11
+
12
+
13
+ def step_name(_, step_match, _, _, _, _)
14
+ pp step_match
15
+ pp step_match.instance_variables
16
+
17
+ # Returns a Cucumber::RbSupport::RbStepDefinition
18
+ pp step_match.instance_variable_get(:@step_definition).class
19
+ pp step_match.instance_variable_get(:@step_definition).object_id
20
+ pp step_match.instance_variable_get(:@name_to_match)
21
+ pp step_match.instance_variable_get(:@step_arguments)
22
+ end
23
+ end # class
24
+
25
+ end # module
data/lib/macro_steps.rb CHANGED
@@ -47,7 +47,7 @@ end
47
47
  # |password|unguessable|
48
48
  When(/^I \[([^\]]+)\]:$/) do |macro_phrase, table_argument|
49
49
  # Ensure that the second argument is of the correct type
50
- unless table_argument.kind_of?(Cucumber::Ast::Table)
50
+ unless table_argument.is_a?(Cucumber::Ast::Table)
51
51
  fail(Macros4Cuke::DataTableNotFound.new(macro_phrase))
52
52
  end
53
53
 
@@ -19,10 +19,10 @@ class Application
19
19
  # Entry point for the application object.
20
20
  def run!(theCmdLineArgs)
21
21
  @options = options_from(theCmdLineArgs)
22
- if options[:setup]
23
- options[:setup].each do |a_path|
24
- setup_project(a_path)
25
- end
22
+ return unless options[:setup]
23
+
24
+ options[:setup].each do |a_path|
25
+ setup_project(a_path)
26
26
  end
27
27
  end
28
28
 
@@ -46,7 +46,8 @@ class Application
46
46
  begin
47
47
  fail SupportFileExists.new(destination) if File.exist?(destination)
48
48
 
49
- template_pathname = Macros4Cuke::RootDir + 'templates/use_macros4cuke.erb'
49
+ template_pathname =
50
+ Macros4Cuke::RootDir + 'templates/use_macros4cuke.erb'
50
51
  template = File.read(template_pathname)
51
52
 
52
53
 
@@ -62,6 +63,7 @@ class Application
62
63
  # Write file contents to file in binary mode in order to avoid eol
63
64
  # consisting of CRLF
64
65
  File.open(destination, 'wb') { |theFile| theFile.write(file_text) }
66
+
65
67
  rescue Macros4Cuke::CmdLineError => exc
66
68
  $stderr.puts exc.message
67
69
  exit
@@ -114,7 +114,7 @@ EOS
114
114
  def validated_feature_path(theProjectPath)
115
115
  dirs = [theProjectPath, 'features', 'support']
116
116
  feature_path = dirs.reduce(Pathname.getwd) do |path, dir_name|
117
- path = path + dir_name
117
+ path += dir_name
118
118
  unless path.exist?
119
119
  fail DirectoryNotFound.new(path.relative_path_from(Pathname.getwd))
120
120
  end
@@ -103,7 +103,7 @@ class CollWalkerFactory
103
103
  end
104
104
 
105
105
 
106
- # Generate an on_section event
106
+ # Generate an on_section event
107
107
  def emit_on_section(current_node, nesting_level, backlog)
108
108
  backlog.unshift(StringNode.new(:on_section_end, nil))
109
109
  add_children(current_node.children, backlog)
@@ -3,7 +3,7 @@
3
3
 
4
4
  module Macros4Cuke # Module used as a namespace
5
5
  # The version number of the gem.
6
- Version = '0.5.03'
6
+ Version = '0.5.06'
7
7
 
8
8
  # Brief description of the gem.
9
9
  Description = 'Add your own macro-steps to Cucumber scenarios'
@@ -11,8 +11,8 @@ module Macros4Cuke # Module used as a namespace
11
11
  # Constant Macros4Cuke::RootDir contains the absolute path of Macro4Cuke's
12
12
  # root directory. Note: it also ends with a slash character.
13
13
  unless defined?(RootDir)
14
- # The initialisation of constant RootDir is guarded in order
15
- # to avoid multiple initialisation (not allowed for constants)
14
+ # The initialisation of constant RootDir is guarded in order
15
+ # to avoid multiple initialisation (not allowed for constants)
16
16
 
17
17
  # The root folder of Macros4Cuke.
18
18
  RootDir = begin
@@ -21,7 +21,7 @@ module Formatter
21
21
  :on_placeholder,
22
22
  :on_section,
23
23
  :on_section_end
24
- ]
24
+ ]
25
25
 
26
26
  end # module
27
27
 
@@ -28,9 +28,9 @@ class ToGherkin
28
28
  return [:on_collection, :on_step, :on_step_end, :on_phrase, :on_source]
29
29
  end
30
30
 
31
- def on_collection(aLevel, aMacroCollection)
31
+ def on_collection(_, _)
32
32
  io.print "# Feature file generated by Macro4Cuke #{Macros4Cuke::Version}"
33
- io.puts " on #{Time.now.strftime('%d/%m/%Y %H:%M:%S')}"
33
+ io.puts " on #{Time.now.strftime('%d/%m/%Y %H:%M:%S')}"
34
34
  io.puts ''
35
35
  io.puts 'Feature: the set of macro-step definitions'
36
36
  io.puts "#{indentation(1)}As a feature file writer"
@@ -38,12 +38,12 @@ class ToGherkin
38
38
  io.puts ''
39
39
  end
40
40
 
41
- def on_step(aLevel, aMacroStep)
41
+ def on_step(aLevel, _)
42
42
  @step_count += 1
43
43
  io.puts "#{indentation(aLevel)}Scenario: Macro #{step_count}"
44
44
  end
45
45
 
46
- def on_step_end(aLevel)
46
+ def on_step_end(_)
47
47
  io.puts ''
48
48
  end
49
49
 
@@ -21,59 +21,59 @@ class ToNull
21
21
  return Formatter::AllNotifications
22
22
  end
23
23
 
24
- def on_collection(aLevel, aMacroCollection)
24
+ def on_collection(_, _)
25
25
  ; # Do nothing
26
26
  end
27
27
 
28
- def on_collection_end(aLevel)
28
+ def on_collection_end(_)
29
29
  ; # Do nothing
30
30
  end
31
31
 
32
- def on_step(aLevel, aMacroStep)
32
+ def on_step(_, _)
33
33
  ; # Do nothing
34
34
  end
35
35
 
36
- def on_step_end(aLevel)
36
+ def on_step_end(_)
37
37
  ; # Do nothing
38
38
  end
39
39
 
40
- def on_phrase(aLevel, aPhraseText, useTable)
40
+ def on_phrase(_, _, _)
41
41
  ; # Do nothing
42
42
  end
43
43
 
44
- def on_renderer(aLevel, aRenderer)
44
+ def on_renderer(_, _)
45
45
  ; # Do nothing
46
46
  end
47
47
 
48
- def on_renderer_end(aLevel)
48
+ def on_renderer_end(_)
49
49
  ; # Do nothing
50
50
  end
51
51
 
52
- def on_source(aLevel, aSourceText)
52
+ def on_source(_, _)
53
53
  ; # Do nothing
54
54
  end
55
55
 
56
- def on_static_text(aLevel, aText)
56
+ def on_static_text(_, _)
57
57
  ; # Do nothing
58
58
  end
59
59
 
60
- def on_comment(aLevel, aComment)
60
+ def on_comment(_, _)
61
61
  ; # Do nothing
62
62
  end
63
63
 
64
- def on_eol(aLevel)
64
+ def on_eol(_)
65
65
  ; # Do nothing
66
66
  end
67
67
 
68
- def on_placeholder(aLevel, aPlaceHolderName)
68
+ def on_placeholder(_, _)
69
69
  ; # Do nothing
70
70
  end
71
71
 
72
- def on_section(aLevel, aSectionName)
72
+ def on_section(_, _)
73
73
  ; # Do Nothing
74
74
  end
75
75
 
76
- def on_section_end(aLevel)
76
+ def on_section_end(_)
77
77
  ; # Do Nothing
78
78
  end
79
79
 
@@ -26,7 +26,7 @@ class ToTrace
26
26
  return Formatter::AllNotifications
27
27
  end
28
28
 
29
- def on_collection(aLevel, aMacroCollection)
29
+ def on_collection(aLevel, _)
30
30
  trace_event(aLevel, __method__)
31
31
  end
32
32
 
@@ -34,7 +34,7 @@ class ToTrace
34
34
  trace_event(aLevel, __method__)
35
35
  end
36
36
 
37
- def on_step(aLevel, aMacroStep)
37
+ def on_step(aLevel, _)
38
38
  trace_event(aLevel, __method__)
39
39
  end
40
40
 
@@ -42,11 +42,11 @@ class ToTrace
42
42
  trace_event(aLevel, __method__)
43
43
  end
44
44
 
45
- def on_phrase(aLevel, aPhraseText, useTable)
45
+ def on_phrase(aLevel, _, _)
46
46
  trace_event(aLevel, __method__)
47
47
  end
48
48
 
49
- def on_renderer(aLevel, aRenderer)
49
+ def on_renderer(aLevel, _)
50
50
  trace_event(aLevel, __method__)
51
51
  end
52
52
 
@@ -54,15 +54,15 @@ class ToTrace
54
54
  trace_event(aLevel, __method__)
55
55
  end
56
56
 
57
- def on_source(aLevel, aSourceText)
57
+ def on_source(aLevel, _)
58
58
  trace_event(aLevel, __method__)
59
59
  end
60
60
 
61
- def on_static_text(aLevel, aStaticText)
61
+ def on_static_text(aLevel, _)
62
62
  trace_event(aLevel, __method__)
63
63
  end
64
64
 
65
- def on_comment(aLevel, aComment)
65
+ def on_comment(aLevel, _)
66
66
  trace_event(aLevel, __method__)
67
67
  end
68
68
 
@@ -70,11 +70,11 @@ class ToTrace
70
70
  trace_event(aLevel, __method__)
71
71
  end
72
72
 
73
- def on_placeholder(aLevel, aPlaceHolderName)
73
+ def on_placeholder(aLevel, _)
74
74
  trace_event(aLevel, __method__)
75
75
  end
76
76
 
77
- def on_section(aLevel, aSectionName)
77
+ def on_section(aLevel, _)
78
78
  trace_event(aLevel, __method__)
79
79
  end
80
80
 
@@ -1,5 +1,5 @@
1
1
  # File: formatting-service.rb
2
- # Purpose: Implementation of the WalkEventPublisher class.
2
+ # Purpose: Implementation of the FormattingService class.
3
3
 
4
4
  require_relative 'exceptions'
5
5
  require_relative 'coll-walker-factory'
@@ -39,9 +39,9 @@ class FormattingService
39
39
 
40
40
  # Check that each event from the event list the formatter is known.
41
41
  supported_events.each do |event|
42
- unless Formatter::AllNotifications.include? event
43
- fail(UnknownFormattingEvent.new(aFormatter, event))
44
- end
42
+ next if Formatter::AllNotifications.include? event
43
+
44
+ fail(UnknownFormattingEvent.new(aFormatter, event))
45
45
  end
46
46
 
47
47
  formatters << aFormatter
@@ -58,11 +58,11 @@ class FormattingService
58
58
  # Notify each formatter of the visit event.
59
59
  formatters.each do |fmt|
60
60
  accepted_notifications = fmt.implements
61
- if accepted_notifications.include? msg
62
- # Assumption: all nil argument(s) are at the end
63
- arg_vector = visit_event[2..-1].reject { |an_arg| an_arg.nil? }
64
- fmt.send(msg, nesting_level, *arg_vector)
65
- end
61
+ next unless accepted_notifications.include? msg
62
+
63
+ # Assumption: all nil argument(s) are at the end
64
+ arg_vector = visit_event[2..-1].reject { |an_arg| an_arg.nil? }
65
+ fmt.send(msg, nesting_level, *arg_vector)
66
66
  end
67
67
  end
68
68
  end
@@ -145,7 +145,7 @@ class MacroStep
145
145
  rawData.each do |a_row|
146
146
  (a_key, value) = validate_row(a_row, macro_parameters)
147
147
  if macro_parameters.include? a_key
148
- if macro_parameters[a_key].kind_of?(Array)
148
+ if macro_parameters[a_key].is_a?(Array)
149
149
  macro_parameters[a_key] << value
150
150
  else
151
151
  macro_parameters[a_key] = [macro_parameters[a_key], value]
@@ -206,18 +206,17 @@ class MacroStep
206
206
  def validate_phrase_args(thePhraseArgs, substepsVars)
207
207
  # Error when the phrase names an argument that never occurs in the substeps
208
208
  thePhraseArgs.each do |phrase_arg|
209
- unless substepsVars.include? phrase_arg
210
- fail(UselessPhraseArgument.new(phrase_arg))
211
- end
209
+ next if substepsVars.include? phrase_arg
210
+ fail(UselessPhraseArgument.new(phrase_arg))
212
211
  end
213
212
  # Error when a substep has an argument that never appears in the phrase
214
213
  # and the macro-step does not use data table.
215
214
  unless use_table?
216
215
  substepsVars.each do |substep_arg|
217
- unless thePhraseArgs.include?(substep_arg) ||
216
+ next if thePhraseArgs.include?(substep_arg) ||
218
217
  BuiltinParameters.include?(substep_arg)
219
- fail(UnreachableSubstepArgument.new(substep_arg))
220
- end
218
+
219
+ fail(UnreachableSubstepArgument.new(substep_arg))
221
220
  end
222
221
  end
223
222
 
@@ -30,7 +30,7 @@ class Comment
30
30
  # Cucumber::RbSupport::RbWorld#steps complains when it sees a comment.
31
31
  # This method has the same signature as the {Engine#render} method.
32
32
  # @return [String] Empty string ("as is")
33
- def render(aContextObject, theLocals)
33
+ def render(_, _)
34
34
  return ''
35
35
  end
36
36
  end # class
@@ -4,6 +4,9 @@
4
4
  require 'strscan' # Use the StringScanner for lexical analysis.
5
5
  require_relative '../exceptions' # Load the custom exception classes.
6
6
 
7
+ require_relative 'static-text'
8
+ require_relative 'eo-line'
9
+ require_relative 'comment'
7
10
  require_relative 'template-element'
8
11
  require_relative 'placeholder'
9
12
  require_relative 'section' # Load the Section and ConditionalSection
@@ -16,76 +19,6 @@ module Macros4Cuke # Module used as a namespace
16
19
  # used internally in Macros4Cuke.
17
20
  module Templating
18
21
 
19
- # Class used internally by the template engine.
20
- # Represents a static piece of text from a template.
21
- # A static text is a text that is reproduced verbatim
22
- # when rendering a template.
23
- class StaticText
24
- # The static text extracted from the original template.
25
- attr_reader(:source)
26
-
27
-
28
- # @param aSourceText [String] A piece of text extracted
29
- # from the template that must be rendered verbatim.
30
- def initialize(aSourceText)
31
- @source = aSourceText
32
- end
33
-
34
- public
35
-
36
- # Render the static text.
37
- # This method has the same signature as the {Engine#render} method.
38
- # @return [String] Static text is returned verbatim ("as is")
39
- def render(aContextObject, theLocals)
40
- return source
41
- end
42
- end # class
43
-
44
-
45
- # Class used internally by the template engine.
46
- # Represents a comment from a template.
47
- # A static text is a text that is reproduced verbatim
48
- # when rendering a template.
49
- class Comment
50
- # The comment as extracted from the original template.
51
- attr_reader(:source)
52
-
53
-
54
- # @param aSourceText [String] A piece of text extracted
55
- # from the template that must be rendered verbatim.
56
- def initialize(aSourceText)
57
- @source = aSourceText
58
- end
59
-
60
- public
61
-
62
- # Render the comment.
63
- # Comments are rendered as empty text. This is necessary because
64
- # Cucumber::RbSupport::RbWorld#steps complains when it sees a comment.
65
- # This method has the same signature as the {Engine#render} method.
66
- # @return [String] Empty string ("as is")
67
- def render(aContextObject, theLocals)
68
- return ''
69
- end
70
- end # class
71
-
72
-
73
- # Class used internally by the template engine.
74
- # Represents an end of line that must be rendered as such.
75
- class EOLine
76
-
77
- public
78
-
79
- # Render an end of line.
80
- # This method has the same signature as the {Engine#render} method.
81
- # @return [String] An end of line marker. Its exact value is OS-dependent.
82
- def render(aContextObject, theLocals)
83
- return "\n"
84
- end
85
- end # class
86
-
87
-
88
-
89
22
  # A very simple implementation of a templating engine.
90
23
  # Earlier versions of Macros4Cuke relied on the logic-less
91
24
  # Mustache template engine.
@@ -168,7 +101,7 @@ class Engine
168
101
  subResult.concat(element.variables)
169
102
 
170
103
  else
171
- # Do nothing
104
+ # Do nothing
172
105
  end
173
106
  end
174
107
 
@@ -213,7 +146,7 @@ class Engine
213
146
  def self.identify_parse_error(aTextLine)
214
147
  # Unsuccessful scanning: we typically have improperly balanced chevrons.
215
148
  # We will analyze the opening and closing chevrons...
216
- # First: replace escaped chevron(s)
149
+ # First: replace escaped chevron(s)
217
150
  no_escaped = aTextLine.gsub(/\\[<>]/, '--')
218
151
 
219
152
  # var. equals count_of(<) - count_of(>): can only be 0 or temporarily 1
@@ -243,9 +176,9 @@ class Engine
243
176
  line_items = self.class.parse(line)
244
177
  line_items.each do |(kind, text)|
245
178
  # A tag text cannot be empty nor blank
246
- if (kind == :dynamic) && text.strip.empty?
247
- fail(EmptyArgumentError.new(line.strip))
248
- end
179
+ next if (kind != :dynamic) || !text.strip.empty?
180
+
181
+ fail(EmptyArgumentError.new(line.strip))
249
182
  end
250
183
 
251
184
  line_items
@@ -18,7 +18,7 @@ class EOLine
18
18
  # Render an end of line.
19
19
  # This method has the same signature as the {Engine#render} method.
20
20
  # @return [String] An end of line marker. Its exact value is OS-dependent.
21
- def render(aContextObject, theLocals)
21
+ def render(_, _)
22
22
  return "\n"
23
23
  end
24
24
  end # class
@@ -42,7 +42,7 @@ class Section < UnaryElement
42
42
  when Section
43
43
  subResult.concat(a_child.variables)
44
44
  else
45
- # Do nothing
45
+ # Do nothing
46
46
  end
47
47
  end
48
48
 
@@ -54,7 +54,7 @@ class Section < UnaryElement
54
54
  # This method has the same signature as the {Engine#render} method.
55
55
  # @return [String] The text value assigned to the placeholder.
56
56
  # Returns an empty string when no value is assigned to the placeholder.
57
- def render(aContextObject, theLocals)
57
+ def render(_, _)
58
58
  msg = "Method Section.#{__method__} must be implemented in subclass."
59
59
  fail(NotImplementedError, msg)
60
60
  end
@@ -28,7 +28,7 @@ class StaticText
28
28
  # Render the static text.
29
29
  # This method has the same signature as the {Engine#render} method.
30
30
  # @return [String] Static text is returned verbatim ("as is")
31
- def render(aContextObject, theLocals)
31
+ def render(_, _)
32
32
  return source
33
33
  end
34
34
  end # class
@@ -75,7 +75,7 @@ describe Application do
75
75
  file_name = 'use_macros4cuke.rb'
76
76
 
77
77
  subject.run!(%w(--setup ./test_dir))
78
- expect(File.exist?(file_path + '/' + file_name)).to be_true
78
+ expect(File.exist?(file_path + '/' + file_name)).to be true
79
79
 
80
80
  File.delete(file_path + '/' + file_name)
81
81
  delete_dirs(file_path)
@@ -87,14 +87,14 @@ describe Application do
87
87
  file_path = '/test_dir/features/support'
88
88
  file_name = 'use_macros4cuke.rb'
89
89
  args = %w(--setup ./test_dir)
90
- my_dir = File.dirname(__FILE__)
90
+ mydir = File.dirname(__FILE__)
91
91
 
92
92
  expect { subject.run!(args) }.not_to raise_error
93
93
 
94
94
  hijack_stderr
95
95
  err_msg = <<-MSG_END
96
96
  Error in command-line:
97
- The file '#{my_dir}/test_dir/features/support/use_macros4cuke.rb' already exists.
97
+ The file '#{mydir}/test_dir/features/support/use_macros4cuke.rb' already exists.
98
98
  MSG_END
99
99
 
100
100
  expect { subject.run!(args) }.to raise_error(SystemExit)
@@ -152,7 +152,7 @@ END_MESSAGE
152
152
  restore_stderr
153
153
  end
154
154
 
155
- it "should complain when project to setup does'nt exist" do
155
+ it "should complain when project to setup doesn't exist" do
156
156
  hijack_stderr
157
157
  err_msg = <<-END_MESSAGE
158
158
  Error in command-line:
@@ -20,7 +20,7 @@ describe CollWalkerFactory do
20
20
  end
21
21
 
22
22
  after(:all) do
23
- # Clear the collection to prevent interference between spec files
23
+ # Clear the collection to prevent interference between spec files
24
24
  macro_coll.clear
25
25
  end
26
26
 
@@ -165,7 +165,7 @@ describe CollWalkerFactory do
165
165
  second_step = macro_coll.macro_steps.values[1]
166
166
  substep_chunks = second_step.renderer.representation.dup
167
167
  substep_chunks.map! do |ck|
168
- if ck.kind_of?(Templating::Section)
168
+ if ck.is_a?(Templating::Section)
169
169
  [ck, ck.children, ck].flatten
170
170
  else
171
171
  ck
@@ -241,7 +241,7 @@ describe CollWalkerFactory do
241
241
  actual = subject.next
242
242
  expect(actual[0]).to eq(event[0])
243
243
  expect(actual[1]).to eq(event[1])
244
- unless event[2].nil?
244
+ if event[2]
245
245
  expected_obj = substep_chunks[i + 1]
246
246
  expect(actual[2]).to eq(expected_obj.send(event[2]))
247
247
  end
@@ -256,7 +256,7 @@ describe CollWalkerFactory do
256
256
  first_step.renderer.representation.insert(2, :not_a_valid_element)
257
257
  err_type = Macros4Cuke::InternalError
258
258
  err_msg = "Don't know how to format a Symbol."
259
- expect { subject.each { |x| } }.to raise_error(err_type, err_msg)
259
+ expect { subject.each { |_| } }.to raise_error(err_type, err_msg)
260
260
  end
261
261
 
262
262
  end # context
@@ -29,7 +29,7 @@ describe ToGherkin do
29
29
  end
30
30
 
31
31
  after(:all) do
32
- # Clear the collection to prevent interference between spec files
32
+ # Clear the collection to prevent interference between spec files
33
33
  macro_coll.clear
34
34
  end
35
35
 
@@ -23,7 +23,7 @@ describe ToNull do
23
23
  end
24
24
 
25
25
  after(:all) do
26
- # Clear the collection to prevent interference between spec files
26
+ # Clear the collection to prevent interference between spec files
27
27
  macro_coll.clear
28
28
  end
29
29
 
@@ -26,7 +26,7 @@ describe ToTrace do
26
26
  end
27
27
 
28
28
  after(:all) do
29
- # Clear the collection to prevent interference between spec files
29
+ # Clear the collection to prevent interference between spec files
30
30
  macro_coll.clear
31
31
  end
32
32
 
@@ -23,7 +23,7 @@ describe FormattingService do
23
23
  end
24
24
 
25
25
  after(:all) do
26
- # Clear the collection to prevent interference between spec files
26
+ # Clear the collection to prevent interference between spec files
27
27
  macro_coll.clear
28
28
  end
29
29
 
@@ -34,7 +34,7 @@ describe FormattingService do
34
34
  end
35
35
 
36
36
  it 'has no formatter at start' do
37
- expect(subject).to have(0).formatters
37
+ expect(subject.formatters).to be_empty
38
38
  end
39
39
 
40
40
  end # context
@@ -43,23 +43,23 @@ describe FormattingService do
43
43
  context 'Provided services:' do
44
44
  it 'should know its registered formatter(s)' do
45
45
  formatter1 = double('fake_one')
46
- formatter1.should_receive(:implements).once.and_return([:on_collection])
46
+ expect(formatter1).to receive(:implements).once.and_return([:on_collection])
47
47
  subject.register(formatter1)
48
- expect(subject).to have(1).formatters
48
+ expect(subject.formatters.size).to eq(1)
49
49
 
50
50
  formatter2 = double('fake_two')
51
- formatter2.should_receive(:implements).once.and_return([:on_step])
51
+ expect(formatter2).to receive(:implements).once.and_return([:on_step])
52
52
  subject.register(formatter2)
53
- expect(subject).to have(2).formatters
53
+ expect(subject.formatters.size).to eq(2)
54
54
 
55
55
  expect(subject.formatters).to eq([formatter1, formatter2])
56
56
  end
57
57
 
58
58
  it "should complain when a formatter doesn't implement notifications" do
59
59
  formatter1 = double('formatter')
60
- formatter1.should_receive(:implements).once.and_return([])
60
+ expect(formatter1).to receive(:implements).once.and_return([])
61
61
  err_type = Macros4Cuke::NoFormattingEventForFormatter
62
- err_msg = 'Formatter RSpec::Mocks::Mock does not'\
62
+ err_msg = 'Formatter RSpec::Mocks::Double does not'\
63
63
  ' support any formatting event.'
64
64
  expect { subject.register(formatter1) }.to raise_error(err_type, err_msg)
65
65
  end
@@ -73,9 +73,9 @@ describe FormattingService do
73
73
  :on_step_end
74
74
  ]
75
75
  formatter = double('formatter')
76
- formatter.should_receive(:implements).once.and_return(notifications)
76
+ expect(formatter).to receive(:implements).once.and_return(notifications)
77
77
  err_type = Macros4Cuke::UnknownFormattingEvent
78
- err_msg = "Formatter RSpec::Mocks::Mock uses\
78
+ err_msg = "Formatter RSpec::Mocks::Double uses\
79
79
  the unknown formatting event 'non_standard'."
80
80
  expect { subject.register(formatter) }.to raise_error(err_type, err_msg)
81
81
  end
@@ -89,28 +89,28 @@ describe FormattingService do
89
89
  :on_step,
90
90
  :on_step_end
91
91
  ]
92
- formatter1.should_receive(:implements)
92
+ expect(formatter1).to receive(:implements)
93
93
  .at_least(69).times
94
94
  .and_return(supported_notifications)
95
95
  subject.register(formatter1)
96
96
 
97
97
  # Test the notifications send to the formatter
98
- formatter1.should_receive(:on_collection).once do |level, coll|
98
+ expect(formatter1).to receive(:on_collection).once do |level, coll|
99
99
  expect(level).to eq(0)
100
100
  expect(coll).to eq(macro_coll)
101
101
  end
102
102
 
103
- formatter1.should_receive(:on_step).twice do |level, a_step|
103
+ expect(formatter1).to receive(:on_step).twice do |level, a_step|
104
104
  expect(level).to eq(1)
105
105
  expect(macro_coll.macro_steps.values).to include(a_step)
106
106
  end
107
107
 
108
- formatter1.should_receive(:on_step_end).twice do |level, arg|
108
+ expect(formatter1).to receive(:on_step_end).twice do |level, arg|
109
109
  expect(level).to eq(1)
110
110
  expect(arg).to be_nil
111
111
  end
112
112
 
113
- formatter1.should_receive(:on_collection_end).once do |level, arg|
113
+ expect(formatter1).to receive(:on_collection_end).once do |level, arg|
114
114
  expect(level).to eq(0)
115
115
  expect(arg).to be_nil
116
116
  end
@@ -120,7 +120,7 @@ describe FormattingService do
120
120
  it 'should support multiple formatters' do
121
121
  formatter1 = double('formatter')
122
122
  supported_notifications = [:on_collection]
123
- formatter1.should_receive(:implements)
123
+ expect(formatter1).to receive(:implements)
124
124
  .at_least(69 * 3).times
125
125
  .and_return(supported_notifications)
126
126
 
@@ -128,7 +128,7 @@ describe FormattingService do
128
128
  3.times { subject.register(formatter1) }
129
129
 
130
130
  # ... then the collection is formatted three times
131
- formatter1.should_receive(:on_collection).at_least(3).times
131
+ expect(formatter1).to receive(:on_collection).at_least(3).times
132
132
  subject.start!(macro_coll)
133
133
  end
134
134
  end # context
@@ -39,7 +39,7 @@ SNIPPET
39
39
  phrase = '[enter my credentials]'
40
40
  args = [phrase, sample_substeps, true]
41
41
  expect { singleton.add_macro(*args) }.not_to raise_error
42
- expect(singleton).to have(1).macro_steps
42
+ expect(singleton.macro_steps.size).to eq(1)
43
43
 
44
44
  # Error case: inserting another macro with same phrase.
45
45
  msg = "A macro-step with phrase '[enter my credentials]' already exists."
@@ -72,7 +72,7 @@ SNIPPET
72
72
 
73
73
  context 'Provided services:' do
74
74
 
75
- let(:phrase_instance) { %Q(enter my credentials as "nobody") }
75
+ let(:phrase_instance) { 'enter my credentials as "nobody"' }
76
76
  it 'should render the substeps' do
77
77
  text = subject.expand(phrase_instance, [ %w(password no-secret) ])
78
78
  expectation = <<-SNIPPET
@@ -101,7 +101,7 @@ SNIPPET
101
101
  end
102
102
 
103
103
  it 'should un-escape the double-quotes for phrase arguments' do
104
- specific_phrase = %q(enter my credentials as "quotable\"")
104
+ specific_phrase = 'enter my credentials as "quotable\""'
105
105
  text = subject.expand(specific_phrase, [ %w(password no-secret) ])
106
106
  expectation = <<-SNIPPET
107
107
  Given I landed in the homepage
@@ -126,7 +126,7 @@ SNIPPET
126
126
 
127
127
  it 'should complain when argument gets a value from phrase and table' do
128
128
  # Error case: there is no macro argument called <unknown>
129
- phrase = %Q(enter my credentials as "nobody")
129
+ phrase = 'enter my credentials as "nobody"'
130
130
  msg = "The macro argument 'userid' has value 'nobody' and 'someone'."
131
131
  args = [ %w(userid someone), %w(password no-secret) ]
132
132
  expect { subject.expand(phrase, args) }.to raise_error(
@@ -65,7 +65,7 @@ SNIPPET
65
65
 
66
66
  # Expectation: an array with one couple:
67
67
  # [:static, the source text]
68
- expect(result).to have(1).items
68
+ expect(result.size).to eq(1)
69
69
  expect(result[0]).to eq([:static, sample_text])
70
70
  end
71
71
 
@@ -75,7 +75,7 @@ SNIPPET
75
75
 
76
76
  # Expectation: an array with one couple:
77
77
  # [:static, the source text]
78
- expect(result).to have(1).items
78
+ expect(result.size).to eq(1)
79
79
  expect(result[0]).to eq([:dynamic, strip_chevrons(sample_text)])
80
80
  end
81
81
 
@@ -85,7 +85,7 @@ SNIPPET
85
85
 
86
86
  # Expectation: an array with two couples:
87
87
  # [dynamic, 'some_tag'][:static, some text]
88
- expect(result).to have(2).items
88
+ expect(result.size).to eq(2)
89
89
  expect(result[0]).to eq([:dynamic, 'some_tag'])
90
90
  expect(result[1]).to eq([:static, 'some text'])
91
91
  end
@@ -96,7 +96,7 @@ SNIPPET
96
96
 
97
97
  # Expectation: an array with two couples:
98
98
  # [:static, some text] [dynamic, 'some_tag']
99
- expect(result).to have(2).items
99
+ expect(result.size).to eq(2)
100
100
  expect(result[0]).to eq([:static, 'some text'])
101
101
  expect(result[1]).to eq([:dynamic, 'some_tag'])
102
102
  end
@@ -106,7 +106,7 @@ SNIPPET
106
106
  result = Engine.parse(sample_text)
107
107
 
108
108
  # Expectation: an array with three couples:
109
- expect(result).to have(3).items
109
+ expect(result.size).to eq(3)
110
110
  expect(result[0]).to eq([:static, 'begin '])
111
111
  expect(result[1]).to eq([:dynamic, 'some_tag'])
112
112
  expect(result[2]).to eq([:static, ' end'])
@@ -117,19 +117,19 @@ SNIPPET
117
117
  result = Engine.parse(sample_text)
118
118
 
119
119
  # Expectation: an array with items couples:
120
- expect(result).to have(5).items
121
- expect(result[0]).to eq([:static , 'begin '])
120
+ expect(result.size).to eq(5)
121
+ expect(result[0]).to eq([:static, 'begin '])
122
122
  expect(result[1]).to eq([:dynamic, 'some_tag'])
123
- expect(result[2]).to eq([:static , 'middle'])
123
+ expect(result[2]).to eq([:static, 'middle'])
124
124
  expect(result[3]).to eq([:dynamic, 'another_tag'])
125
- expect(result[4]).to eq([:static, ' end'])
125
+ expect(result[4]).to eq([:static, ' end'])
126
126
 
127
127
  # Case: two consecutive tags
128
128
  sample_text = 'begin <some_tag><another_tag> end'
129
129
  result = Engine.parse(sample_text)
130
130
 
131
131
  # Expectation: an array with four couples:
132
- expect(result).to have(4).items
132
+ expect(result.size).to eq(4)
133
133
  expect(result[0]).to eq([:static, 'begin '])
134
134
  expect(result[1]).to eq([:dynamic, 'some_tag'])
135
135
  expect(result[2]).to eq([:dynamic, 'another_tag'])
@@ -141,7 +141,7 @@ SNIPPET
141
141
  result = Engine.parse(sample_text)
142
142
 
143
143
  # Expectation: an array with one couple: [:static, the source text]
144
- expect(result).to have(1).items
144
+ expect(result.size).to eq(1)
145
145
  expect(result[0]).to eq([:static, sample_text])
146
146
  end
147
147
 
@@ -150,7 +150,7 @@ SNIPPET
150
150
  result = Engine.parse(sample_text)
151
151
 
152
152
  # Expectation: an array with three couples:
153
- expect(result).to have(3).items
153
+ expect(result.size).to eq(3)
154
154
  expect(result[0]).to eq([:static, 'begin '])
155
155
  expect(result[1]).to eq([:dynamic, 'some_\<\\>weird\>_tag'])
156
156
  expect(result[2]).to eq([:static, ' end'])
@@ -163,14 +163,14 @@ SNIPPET
163
163
  StandardError, error_message)
164
164
  end
165
165
 
166
- it 'should complain if a text misses an opening chevron' do
166
+ it 'should complain if a text misses an opening chevron' do
167
167
  sample_text = 'begin <some_tag> > end'
168
168
  error_message = "Missing opening chevron '<'."
169
169
  expect { Engine.parse(sample_text) }.to raise_error(
170
170
  StandardError, error_message)
171
171
  end
172
172
 
173
- it 'should complain if a text has nested opening chevrons' do
173
+ it 'should complain if a text has nested opening chevrons' do
174
174
  sample_text = 'begin <<some_tag> > end'
175
175
  error_message = "Nested opening chevron '<'."
176
176
  expect { Engine.parse(sample_text) }.to raise_error(
@@ -309,7 +309,7 @@ SNIPPET
309
309
 
310
310
  locals = {
311
311
  'firstname' => 'Anon',
312
- 'lastname' => 'Eemoos' ,
312
+ 'lastname' => 'Eemoos',
313
313
  'birthdate' => '1976-04-21'
314
314
  }
315
315
  rendered_text = instance.render(Object.new, locals)
@@ -36,7 +36,7 @@ describe Section do
36
36
  end
37
37
 
38
38
  it 'should have no child at start' do
39
- expect(subject).to have(0).children
39
+ expect(subject.children).to be_empty
40
40
  end
41
41
 
42
42
  end # context
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: macros4cuke
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.03
4
+ version: 0.5.06
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-01 00:00:00.000000000 Z
11
+ date: 2014-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cucumber
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - ! '>='
46
46
  - !ruby/object:Gem::Version
47
- version: 2.11.0
47
+ version: 3.0.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ! '>='
53
53
  - !ruby/object:Gem::Version
54
- version: 2.11.0
54
+ version: 3.0.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: simplecov
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -156,6 +156,7 @@ files:
156
156
  - features/README.md
157
157
  - features/step_definitions/demo_steps.rb
158
158
  - features/support/env.rb
159
+ - features/support/my_formatter.rb
159
160
  - features/support/use_macros4cuke.rb
160
161
  - spec/macros4cuke/application_spec.rb
161
162
  - spec/macros4cuke/cli/cmd-line_spec.rb