lucid 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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