lucid 0.3.3 → 0.4.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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +13 -9
  3. data/README.md +2 -6
  4. data/lib/lucid.rb +22 -3
  5. data/lib/lucid/{term/ansicolor.rb → ansicolor.rb} +34 -41
  6. data/lib/lucid/ast.rb +2 -2
  7. data/lib/lucid/ast/outline_table.rb +2 -2
  8. data/lib/lucid/ast/{specs.rb → spec.rb} +10 -1
  9. data/lib/lucid/ast/step.rb +3 -3
  10. data/lib/lucid/ast/step_invocation.rb +16 -16
  11. data/lib/lucid/ast/table.rb +1 -1
  12. data/lib/lucid/ast/{tdl_walker.rb → walker.rb} +15 -16
  13. data/lib/lucid/cli/app.rb +23 -21
  14. data/lib/lucid/cli/{configuration.rb → context.rb} +66 -38
  15. data/lib/lucid/cli/options.rb +59 -40
  16. data/lib/lucid/{configuration.rb → context.rb} +2 -3
  17. data/lib/lucid/{runtime.rb → context_loader.rb} +58 -61
  18. data/lib/lucid/{runtime/facade.rb → facade.rb} +5 -6
  19. data/lib/lucid/formatter/ansicolor.rb +15 -14
  20. data/lib/lucid/formatter/debug.rb +1 -1
  21. data/lib/lucid/formatter/usage.rb +2 -2
  22. data/lib/lucid/interface.rb +121 -0
  23. data/lib/lucid/{runtime/interface_io.rb → interface_io.rb} +2 -2
  24. data/lib/lucid/interface_rb/rb_language.rb +6 -23
  25. data/lib/lucid/interface_rb/rb_step_definition.rb +1 -2
  26. data/lib/lucid/{core_ext/instance_exec.rb → lang_extend.rb} +112 -69
  27. data/lib/lucid/{runtime/orchestrator.rb → orchestrator.rb} +36 -24
  28. data/lib/lucid/platform.rb +1 -1
  29. data/lib/lucid/{runtime/results.rb → results.rb} +10 -10
  30. data/lib/lucid/{tdl_builder.rb → spec_builder.rb} +26 -22
  31. data/lib/lucid/spec_file.rb +33 -13
  32. data/lib/lucid/{runtime/specs_loader.rb → spec_loader.rb} +13 -22
  33. data/lib/lucid/{step_definition_light.rb → step_definition_usage.rb} +2 -4
  34. data/lib/lucid/step_definitions.rb +4 -4
  35. data/spec/lucid/app_spec.rb +6 -18
  36. data/spec/lucid/ast/background_spec.rb +4 -4
  37. data/spec/lucid/ast/feature_spec.rb +7 -7
  38. data/spec/lucid/ast/scenario_outline_spec.rb +9 -9
  39. data/spec/lucid/ast/specs_spec.rb +8 -8
  40. data/spec/lucid/ast/step_spec.rb +5 -5
  41. data/spec/lucid/ast/tdl_walker_spec.rb +5 -5
  42. data/spec/lucid/{configuration_spec.rb → context_spec.rb} +78 -78
  43. data/spec/lucid/facade_spec.rb +7 -7
  44. data/spec/lucid/orchestrator_spec.rb +7 -7
  45. data/spec/lucid/pending_spec.rb +3 -3
  46. data/spec/lucid/progress_spec.rb +3 -3
  47. data/spec/lucid/rb_step_definition_spec.rb +4 -4
  48. data/spec/lucid/results_spec.rb +2 -2
  49. data/spec/lucid/runtime_spec.rb +7 -7
  50. metadata +20 -32
  51. data/bin/lucid-gen +0 -4
  52. data/lib/lucid/core_ext/proc.rb +0 -36
  53. data/lib/lucid/core_ext/string.rb +0 -9
  54. data/lib/lucid/generator.rb +0 -21
  55. data/lib/lucid/generators/project.rb +0 -64
  56. data/lib/lucid/generators/project/Gemfile.tt +0 -6
  57. data/lib/lucid/generators/project/browser-fluent.rb +0 -37
  58. data/lib/lucid/generators/project/driver-fluent.rb +0 -1
  59. data/lib/lucid/generators/project/errors.rb +0 -26
  60. data/lib/lucid/generators/project/events-fluent.rb +0 -33
  61. data/lib/lucid/interface_methods.rb +0 -125
@@ -1,6 +1,5 @@
1
1
  module Lucid
2
- # The base class for configuring settings for a Lucid run.
3
- class Configuration
2
+ class Context
4
3
  def self.default
5
4
  new
6
5
  end
@@ -46,7 +45,7 @@ module Lucid
46
45
 
47
46
  def default_options
48
47
  {
49
- :autoload_code_paths => ['common', 'steps', 'pages']
48
+ :autoload_code_paths => %w(common steps pages)
50
49
  }
51
50
  end
52
51
  end
@@ -2,59 +2,56 @@ require 'fileutils'
2
2
  require 'multi_json'
3
3
  require 'gherkin/rubify'
4
4
  require 'gherkin/i18n'
5
- require 'lucid/configuration'
5
+ require 'lucid/context'
6
6
  require 'lucid/load_path'
7
- require 'lucid/interface_methods'
7
+ require 'lucid/interface'
8
8
  require 'lucid/formatter/duration'
9
- require 'lucid/runtime/interface_io'
10
- require 'lucid/runtime/specs_loader'
11
- require 'lucid/runtime/results'
12
- require 'lucid/runtime/orchestrator'
9
+ require 'lucid/interface_io'
10
+ require 'lucid/spec_loader'
11
+ require 'lucid/results'
12
+ require 'lucid/orchestrator'
13
13
 
14
14
  module Lucid
15
- class Runtime
15
+ class ContextLoader
16
16
  attr_reader :results, :orchestrator
17
17
 
18
18
  include Formatter::Duration
19
- include Runtime::InterfaceIO
20
-
21
- def initialize(configuration = Configuration.default)
22
- if defined?(Test::Unit::Runner)
23
- Test::Unit::Runner.module_eval("@@stop_auto_run = true")
24
- end
19
+ include ContextLoader::InterfaceIO
25
20
 
21
+ def initialize(context = Context.default)
26
22
  @current_scenario = nil
27
- @configuration = Configuration.parse(configuration)
28
- @orchestrator = Orchestrator.new(self, @configuration)
29
- @results = Results.new(@configuration)
23
+ @context = Context.parse(context)
24
+ @orchestrator = Orchestrator.new(self, @context)
25
+ @results = Results.new(@context)
30
26
  end
31
27
 
32
- # Used to take an existing runtime and change its configuration.
33
- def configure(new_configuration)
34
- @configuration = Configuration.parse(new_configuration)
35
- @orchestrator.configure(@configuration)
36
- @results.configure(@configuration)
28
+ # Used to take an existing Lucid operation context and change the
29
+ # configuration of that context.
30
+ def configure(new_context)
31
+ @context = Context.parse(new_context)
32
+ @orchestrator.configure(@context)
33
+ @results.configure(@context)
37
34
  end
38
35
 
39
36
  def load_code_language(language)
40
37
  @orchestrator.load_code_language(language)
41
38
  end
42
39
 
43
- def run
40
+ def execute
44
41
  load_execution_context
45
42
  fire_after_configuration_hook
46
43
 
47
- tdl_walker = @configuration.establish_tdl_walker(self)
48
- self.visitor = tdl_walker
44
+ ast_walker = @context.establish_ast_walker(self)
45
+ self.visitor = ast_walker
49
46
 
50
- specs.accept(tdl_walker)
47
+ load_spec_context.accept(ast_walker)
51
48
  end
52
49
 
53
50
  def specs_paths
54
- @configuration.spec_source
51
+ @context.spec_source
55
52
  end
56
53
 
57
- def step_visited(step) #:nodoc:
54
+ def step_visited(step)
58
55
  @results.step_visited(step)
59
56
  end
60
57
 
@@ -66,7 +63,7 @@ module Lucid
66
63
  @results.steps(status)
67
64
  end
68
65
 
69
- def step_match(step_name, name_to_report=nil) #:nodoc:
66
+ def step_match(step_name, name_to_report=nil)
70
67
  @orchestrator.step_match(step_name, name_to_report)
71
68
  end
72
69
 
@@ -74,7 +71,7 @@ module Lucid
74
71
  @orchestrator.unmatched_step_definitions
75
72
  end
76
73
 
77
- def matcher_text(step_keyword, step_name, multiline_arg_class) #:nodoc:
74
+ def matcher_text(step_keyword, step_name, multiline_arg_class)
78
75
  @orchestrator.matcher_text(Gherkin::I18n.code_keyword_for(step_keyword), step_name, multiline_arg_class)
79
76
  end
80
77
 
@@ -86,7 +83,7 @@ module Lucid
86
83
  end
87
84
  end
88
85
 
89
- def around(scenario, skip_hooks=false, &block) #:nodoc:
86
+ def around(scenario, skip_hooks=false, &block)
90
87
  if skip_hooks
91
88
  yield
92
89
  return
@@ -95,27 +92,27 @@ module Lucid
95
92
  @orchestrator.around(scenario, block)
96
93
  end
97
94
 
98
- def before_and_after(scenario, skip_hooks=false) #:nodoc:
95
+ def before_and_after(scenario, skip_hooks=false)
99
96
  before(scenario) unless skip_hooks
100
97
  yield scenario
101
98
  after(scenario) unless skip_hooks
102
99
  @results.scenario_visited(scenario)
103
100
  end
104
101
 
105
- def before(scenario) #:nodoc:
106
- return if @configuration.dry_run? || @current_scenario
102
+ def before(scenario)
103
+ return if @context.dry_run? || @current_scenario
107
104
  @current_scenario = scenario
108
105
  @orchestrator.fire_hook(:before, scenario)
109
106
  end
110
107
 
111
- def after(scenario) #:nodoc:
108
+ def after(scenario)
112
109
  @current_scenario = nil
113
- return if @configuration.dry_run?
110
+ return if @context.dry_run?
114
111
  @orchestrator.fire_hook(:after, scenario)
115
112
  end
116
113
 
117
114
  def after_step #:nodoc:
118
- return if @configuration.dry_run?
115
+ return if @context.dry_run?
119
116
  @orchestrator.fire_hook(:execute_after_step, @current_scenario)
120
117
  end
121
118
 
@@ -124,7 +121,7 @@ module Lucid
124
121
  end
125
122
 
126
123
  def write_testdefs_json
127
- if(@configuration.testdefs)
124
+ if(@context.testdefs)
128
125
  stepdefs = []
129
126
  @orchestrator.step_definitions.sort{|a,b| a.to_hash['source'] <=> a.to_hash['source']}.each do |stepdef|
130
127
  stepdef_hash = stepdef.to_hash
@@ -151,24 +148,23 @@ module Lucid
151
148
  stepdef_hash['steps'] = steps.uniq.sort {|a,b| a['name'] <=> b['name']}
152
149
  stepdefs << stepdef_hash
153
150
  end
154
- if !File.directory?(@configuration.testdefs)
155
- FileUtils.mkdir_p(@configuration.testdefs)
151
+ if !File.directory?(@context.testdefs)
152
+ FileUtils.mkdir_p(@context.testdefs)
156
153
  end
157
- File.open(File.join(@configuration.testdefs, 'testdefs.json'), 'w') do |io|
154
+ File.open(File.join(@context.testdefs, 'testdefs.json'), 'w') do |io|
158
155
  io.write(MultiJson.dump(stepdefs, :pretty => true))
159
156
  end
160
157
  end
161
158
  end
162
159
 
163
- # Returns AST::DocString for +string_without_triple_quotes+.
164
- def doc_string(string_without_triple_quotes, content_type='', line_offset=0)
165
- AST::DocString.new(string_without_triple_quotes,content_type)
160
+ def doc_string(non_docstring, content_type='', line_offset=0)
161
+ Lucid::AST::DocString.new(non_docstring, content_type)
166
162
  end
167
163
 
168
- private
164
+ private
169
165
 
170
- def fire_after_configuration_hook #:nodoc
171
- @orchestrator.fire_hook(:after_configuration, @configuration)
166
+ def fire_after_configuration_hook
167
+ @orchestrator.fire_hook(:after_configuration, @context)
172
168
  end
173
169
 
174
170
  # The specs is used to begin loading the executable specs. This is as
@@ -176,22 +172,23 @@ module Lucid
176
172
  # already handled. A SpecsLoader instance is created and this is what
177
173
  # makes sure that a spec file can be turned into a code construct
178
174
  # (a SpecFile instance) which in turn can be broken down into an AST.
179
- def specs
180
- @loader ||= Runtime::SpecsLoader.new(
181
- @configuration.spec_files,
182
- @configuration.filters,
183
- @configuration.tag_expression)
184
- @loader.specs
185
- end
186
-
187
- # Loading the execution context means getting all of the loadable files
188
- # in the spec repository. Loadable files means any code language type
189
- # files. These files are sent to an orchestrator instance that will be
190
- # responsible for loading them. The loading of these files provides the
191
- # execution context for Lucid as it runs executable specs.
175
+ #
176
+ # @return [Object] Instance of Lucid::AST::Spec
177
+ def load_spec_context
178
+ @loader ||= Lucid::ContextLoader::SpecLoader.new(
179
+ @context.spec_context,
180
+ @context.filters,
181
+ @context.tag_expression)
182
+ @loader.load_specs
183
+ end
184
+
185
+ # Determines what files should be included as part of the execution
186
+ # context for Lucid as it runs executable specs. The "library" refers
187
+ # to code that will be common to all specs while "definition" refers
188
+ # to page/activity definitions as well as test definitions, which are
189
+ # usually referred to as steps.
192
190
  def load_execution_context
193
- files = @configuration.library_context + @configuration.definition_context
194
- log.info("Runtime Load Execution Context: #{files}")
191
+ files = @context.library_context + @context.definition_context
195
192
  @orchestrator.load_files(files)
196
193
  end
197
194
 
@@ -1,7 +1,7 @@
1
1
  require 'forwardable'
2
2
 
3
3
  module Lucid
4
- class Runtime
4
+ class ContextLoader
5
5
  # This is what a programming language will consider to be a runtime.
6
6
  #
7
7
  # It's a thin class that directs the specific methods needed by the
@@ -43,15 +43,14 @@ module Lucid
43
43
  #
44
44
  def table(text_or_table, file=nil, line_offset=0)
45
45
  if Array === text_or_table
46
- AST::Table.new(text_or_table)
46
+ Lucid::AST::Table.new(text_or_table)
47
47
  else
48
- AST::Table.parse(text_or_table, file, line_offset)
48
+ Lucid::AST::Table.parse(text_or_table, file, line_offset)
49
49
  end
50
50
  end
51
51
 
52
- # Returns AST::DocString
53
- def doc_string(string_without_triple_quotes, content_type='', line_offset=0)
54
- AST::DocString.new(string_without_triple_quotes,content_type)
52
+ def doc_string(non_docstring, content_type='', line_offset=0)
53
+ Lucid::AST::DocString.new(non_docstring, content_type)
55
54
  end
56
55
  end
57
56
  end
@@ -1,17 +1,17 @@
1
1
  require 'lucid/platform'
2
- require 'lucid/term/ansicolor'
2
+ require 'lucid/ansicolor'
3
3
 
4
4
  if Lucid::IRONRUBY
5
5
  begin
6
6
  require 'iron-term-ansicolor'
7
7
  rescue LoadError
8
- STDERR.puts %{*** WARNING: You must "gem install iron-term-ansicolor" to get colored ouput in on IronRuby}
8
+ STDERR.puts %{*** WARNING: You must "gem install iron-term-ansicolor" to get colored ouput with IronRuby}
9
9
  end
10
10
  end
11
11
 
12
12
  if Lucid::WINDOWS_MRI
13
13
  unless ENV['ANSICON']
14
- STDERR.puts %{*** WARNING: You must use ANSICON 1.31 or higher (https://github.com/adoxa/ansicon/) to get colored output on Windows}
14
+ STDERR.puts %{*** WARNING: You must use ANSICON (https://github.com/adoxa/ansicon/) to get colored output on Windows}
15
15
  Lucid::Term::ANSIColor.coloring = false
16
16
  end
17
17
  end
@@ -74,7 +74,8 @@ module Lucid
74
74
  'tag' => 'cyan'
75
75
  })
76
76
 
77
- if ENV['LUCID_COLORS'] # Example: export LUCID_COLORS="passed=red:failed=yellow"
77
+ # Example: export LUCID_COLORS="passed=red:failed=yellow"
78
+ if ENV['LUCID_COLORS']
78
79
  ENV['LUCID_COLORS'].split(':').each do |pair|
79
80
  a = pair.split('=')
80
81
  ALIASES[a[0]] = a[1]
@@ -126,7 +127,7 @@ module Lucid
126
127
  if e.class.name == 'TermInfo::TermInfoError'
127
128
  STDERR.puts '*** WARNING ***'
128
129
  STDERR.puts "You have the genki-ruby-terminfo gem installed, but you haven't set your TERM variable."
129
- STDERR.puts 'Try setting it to TERM=xterm-256color to get grey color in output.'
130
+ STDERR.puts 'Try setting it to TERM=xterm-256color to get color in output.'
130
131
  STDERR.puts "\n"
131
132
  alias grey white
132
133
  else
@@ -135,8 +136,8 @@ module Lucid
135
136
  end
136
137
  end
137
138
 
138
- def self.define_real_grey #:nodoc:
139
- def grey(string) #:nodoc:
139
+ def self.define_real_grey
140
+ def grey(string)
140
141
  if ::Lucid::Term::ANSIColor.coloring?
141
142
  "\e[90m#{string}\e[0m"
142
143
  else
@@ -147,20 +148,20 @@ module Lucid
147
148
 
148
149
  define_grey
149
150
 
150
- def cukes(n)
151
+ def lucid(n)
151
152
  ('(::) ' * n).strip
152
153
  end
153
154
 
154
- def green_cukes(n)
155
- blink(green(cukes(n)))
155
+ def green_lucid(n)
156
+ blink(green(lucid(n)))
156
157
  end
157
158
 
158
- def red_cukes(n)
159
- blink(red(cukes(n)))
159
+ def red_lucid(n)
160
+ blink(red(lucid(n)))
160
161
  end
161
162
 
162
- def yellow_cukes(n)
163
- blink(yellow(cukes(n)))
163
+ def yellow_lucid(n)
164
+ blink(yellow(lucid(n)))
164
165
  end
165
166
  end
166
167
  end
@@ -1,5 +1,5 @@
1
1
  require 'lucid/formatter/progress'
2
- require 'lucid/step_definition_light'
2
+ require 'lucid/step_definition_usage'
3
3
 
4
4
  module Lucid
5
5
  module Formatter
@@ -1,12 +1,12 @@
1
1
  require 'lucid/formatter/progress'
2
- require 'lucid/step_definition_light'
2
+ require 'lucid/step_definition_usage'
3
3
 
4
4
  module Lucid
5
5
  module Formatter
6
6
  class Usage < Progress
7
7
  include Console
8
8
 
9
- class StepDefKey < StepDefinitionLight
9
+ class StepDefKey < StepDefinitionUsage
10
10
  attr_accessor :mean_duration, :status
11
11
  end
12
12
 
@@ -1,8 +1,129 @@
1
+ require 'lucid/step_match'
2
+ require 'lucid/step_definition_usage'
3
+
1
4
  module Lucid
2
5
  # This module defines the API for programming language support in Lucid.
3
6
  # While Lucid itself is written in Ruby, any programming language can
4
7
  # be supported by implementing this API. Each language implementation
5
8
  # must manage its own events and must execute them at appropriate times.
6
9
  module Interface
10
+ module InterfaceMethods
11
+ def around(scenario)
12
+ execute_around(scenario) do
13
+ yield
14
+ end
15
+ end
16
+
17
+ def before(scenario)
18
+ begin_scenario(scenario)
19
+ execute_before(scenario)
20
+ end
21
+
22
+ def after(scenario)
23
+ execute_after(scenario)
24
+ end_scenario
25
+ end
26
+
27
+ def after_configuration(configuration)
28
+ hooks[:after_configuration].each do |hook|
29
+ hook.invoke('AfterConfiguration', configuration)
30
+ end
31
+ end
32
+
33
+ def execute_after_step(scenario)
34
+ hooks_for(:after_step, scenario).each do |hook|
35
+ invoke(hook, 'AfterStep', scenario, false)
36
+ end
37
+ end
38
+
39
+ def execute_transforms(args)
40
+ args.map do |arg|
41
+ matching_transform = transforms.detect {|transform| transform.match(arg) }
42
+ matching_transform ? matching_transform.invoke(arg) : arg
43
+ end
44
+ end
45
+
46
+ def add_hook(phase, hook)
47
+ hooks[phase.to_sym] << hook
48
+ hook
49
+ end
50
+
51
+ def clear_hooks
52
+ @hooks = nil
53
+ end
54
+
55
+ def add_transform(transform)
56
+ transforms.unshift transform
57
+ transform
58
+ end
59
+
60
+ def hooks_for(phase, scenario) #:nodoc:
61
+ hooks[phase.to_sym].select{|hook| scenario.accept_hook?(hook)}
62
+ end
63
+
64
+ def unmatched_step_definitions
65
+ available_step_definition_hash.keys - invoked_step_definition_hash.keys
66
+ end
67
+
68
+ def available_step_definition(regexp_source, file_colon_line)
69
+ available_step_definition_hash[StepDefinitionUsage.new(regexp_source, file_colon_line)] = nil
70
+ end
71
+
72
+ def invoked_step_definition(regexp_source, file_colon_line)
73
+ invoked_step_definition_hash[StepDefinitionUsage.new(regexp_source, file_colon_line)] = nil
74
+ end
75
+
76
+ private
77
+
78
+ def available_step_definition_hash
79
+ @available_step_definition_hash ||= {}
80
+ end
81
+
82
+ def invoked_step_definition_hash
83
+ @invoked_step_definition_hash ||= {}
84
+ end
85
+
86
+ def hooks
87
+ @hooks ||= Hash.new{|h,k| h[k] = []}
88
+ end
89
+
90
+ def transforms
91
+ @transforms ||= []
92
+ end
93
+
94
+ def execute_around(scenario, &block)
95
+ hooks_for(:around, scenario).reverse.inject(block) do |blk, hook|
96
+ proc do
97
+ invoke(hook, 'Around', scenario, true) do
98
+ blk.call(scenario)
99
+ end
100
+ end
101
+ end.call
102
+ end
103
+
104
+ def execute_before(scenario)
105
+ hooks_for(:before, scenario).each do |hook|
106
+ invoke(hook, 'Before', scenario, true)
107
+ end
108
+ end
109
+
110
+ def execute_after(scenario)
111
+ hooks_for(:after, scenario).reverse_each do |hook|
112
+ invoke(hook, 'After', scenario, true)
113
+ end
114
+ end
115
+
116
+ def invoke(hook, location, scenario, exception_fails_scenario, &block)
117
+ begin
118
+ hook.invoke(location, scenario, &block)
119
+ rescue Exception => exception
120
+ if exception_fails_scenario
121
+ scenario.fail!(exception)
122
+ else
123
+ raise
124
+ end
125
+ end
126
+ end
127
+ end
7
128
  end
8
129
  end