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,7 +1,7 @@
1
1
  require 'timeout'
2
2
 
3
3
  module Lucid
4
- class Runtime
4
+ class ContextLoader
5
5
 
6
6
  module InterfaceIO
7
7
  attr_writer :visitor
@@ -33,7 +33,7 @@ module Lucid
33
33
  @visitor.embed(src, mime_type, label)
34
34
  end
35
35
 
36
- private
36
+ private
37
37
 
38
38
  def mri_gets(timeout_seconds)
39
39
  begin
@@ -1,4 +1,4 @@
1
- require 'lucid/core_ext/instance_exec'
1
+ require 'lucid/lang_extend'
2
2
  require 'lucid/interface_rb/rb_lucid'
3
3
  require 'lucid/interface_rb/rb_world'
4
4
  require 'lucid/interface_rb/rb_step_definition'
@@ -9,42 +9,32 @@ require 'lucid/interface_rb/matcher'
9
9
  begin
10
10
  require 'rspec/expectations'
11
11
  rescue LoadError
12
- begin
13
- require 'spec/expectations'
14
- require 'spec/runner/differs/default'
15
- require 'ostruct'
16
- rescue LoadError
17
- require 'test/unit/assertions'
18
- end
12
+ require 'test/unit/assertions'
19
13
  end
20
14
 
21
15
  module Lucid
22
16
  module InterfaceRb
23
17
  class NilDomain < StandardError
24
18
  def initialize
25
- super("Domain procs should never return nil")
19
+ super('Domain procs should never return nil.')
26
20
  end
27
21
  end
28
22
 
29
- # Raised if there are 2 or more Domain blocks.
30
23
  class MultipleDomain < StandardError
31
24
  def initialize(first_proc, second_proc)
32
25
  message = "You can only pass a proc to #Domain once, but it's happening\n"
33
26
  message << "in two places:\n\n"
34
27
  message << first_proc.backtrace_line('Domain') << "\n"
35
28
  message << second_proc.backtrace_line('Domain') << "\n\n"
36
- message << "Use Ruby modules instead to extend your worlds. See the Lucid::InterfaceRb::RbLucid#Domain RDoc\n"
29
+ message << "Use Ruby modules instead to extend your worlds.\n"
37
30
  super(message)
38
31
  end
39
32
  end
40
33
 
41
- # This module is the Ruby implementation of the TDL API.
42
34
  class RbLanguage
43
35
  include Interface::InterfaceMethods
44
36
  attr_reader :current_domain, :step_definitions
45
37
 
46
- # Get the expressions of various I18n translations of TDL keywords.
47
- # In this case the TDL is based on Gherkin.
48
38
  Gherkin::I18n.code_keywords.each do |adverb|
49
39
  RbLucid.alias_adverb(adverb)
50
40
  end
@@ -61,14 +51,7 @@ module Lucid
61
51
  begin
62
52
  ::RSpec::Matchers
63
53
  rescue NameError
64
- # RSpec >=1.2.4
65
- begin
66
- options = OpenStruct.new(:diff_format => :unified, :context_lines => 3)
67
- Spec::Expectations.differ = Spec::Expectations::Differs::Default.new(options)
68
- ::Spec::Matchers
69
- rescue NameError
70
- ::Test::Unit::Assertions
71
- end
54
+ ::Test::Unit::Assertions
72
55
  end
73
56
  end
74
57
 
@@ -162,7 +145,7 @@ module Lucid
162
145
  raise NilDomain.new
163
146
  rescue NilDomain => e
164
147
  e.backtrace.clear
165
- e.backtrace.push(proc.backtrace_line("Domain"))
148
+ e.backtrace.push(proc.backtrace_line('Domain'))
166
149
  raise e
167
150
  end
168
151
  else
@@ -1,6 +1,5 @@
1
1
  require 'lucid/step_match'
2
- require 'lucid/core_ext/string'
3
- require 'lucid/core_ext/proc'
2
+ require 'lucid/lang_extend'
4
3
  require 'lucid/interface_rb/regexp_argument_matcher'
5
4
 
6
5
  module Lucid
@@ -1,69 +1,112 @@
1
- require 'lucid/platform'
2
-
3
- module Lucid
4
- # Raised if the number of a StepDefinition's Regexp match groups
5
- # is different from the number of Proc arguments.
6
- class ArityMismatchError < StandardError
7
- end
8
- end
9
-
10
- class Object #:nodoc:
11
- # TODO: Move most of this stuff out to an InstanceExecutor class.
12
- def lucid_instance_exec(check_arity, pseudo_method, *args, &block)
13
- lucid_run_with_backtrace_filtering(pseudo_method) do
14
- if check_arity && !lucid_compatible_arity?(args, block)
15
- instance_exec do
16
- ari = block.arity
17
- ari = ari < 0 ? (ari.abs-1).to_s+"+" : ari
18
- s1 = ari == 1 ? "" : "s"
19
- s2 = args.length == 1 ? "" : "s"
20
- raise Lucid::ArityMismatchError.new(
21
- "Your block takes #{ari} argument#{s1}, but the regexp matched #{args.length} argument#{s2}."
22
- )
23
- end
24
- else
25
- instance_exec(*args, &block)
26
- end
27
- end
28
- end
29
-
30
- private
31
-
32
- def lucid_compatible_arity?(args, block)
33
- return true if block.arity == args.length
34
- if block.arity < 0
35
- return true if args.length >= (block.arity.abs - 1)
36
- end
37
- false
38
- end
39
-
40
- def lucid_run_with_backtrace_filtering(pseudo_method)
41
- begin
42
- yield
43
- rescue Exception => e
44
- instance_exec_invocation_line = "#{__FILE__}:#{__LINE__ - 2}:in `lucid_run_with_backtrace_filtering'"
45
- replace_instance_exec_invocation_line!((e.backtrace || []), instance_exec_invocation_line, pseudo_method)
46
- raise e
47
- end
48
- end
49
-
50
- INSTANCE_EXEC_OFFSET = (Lucid::RUBY_2_0 || Lucid::RUBY_1_9 || Lucid::JRUBY) ? -3 : -4
51
-
52
- def replace_instance_exec_invocation_line!(backtrace, instance_exec_invocation_line, pseudo_method)
53
- return if Lucid.use_full_backtrace
54
-
55
- instance_exec_pos = backtrace.index(instance_exec_invocation_line)
56
- if instance_exec_pos
57
- replacement_line = instance_exec_pos + INSTANCE_EXEC_OFFSET
58
- backtrace[replacement_line].gsub!(/`.*'/, "`#{pseudo_method}'") if pseudo_method
59
-
60
- depth = backtrace.count { |line| line == instance_exec_invocation_line }
61
- end_pos = depth > 1 ? instance_exec_pos : -1
62
-
63
- backtrace[replacement_line+1..end_pos] = nil
64
- backtrace.compact!
65
- else
66
- # Not sure what should happen here.
67
- end
68
- end
69
- end
1
+ require 'lucid/platform'
2
+
3
+ module Lucid
4
+ # Raised if the number of a StepDefinition's Regexp match groups
5
+ # is different from the number of Proc arguments.
6
+ class ArityMismatchError < StandardError
7
+ end
8
+ end
9
+
10
+ class String
11
+ def indent(n)
12
+ if n >= 0
13
+ gsub(/^/, ' ' * n)
14
+ else
15
+ gsub(/^ {0,#{-n}}/, '')
16
+ end
17
+ end
18
+ end
19
+
20
+ class Proc
21
+ PROC_PATTERN = /[\d\w]+@(.+):(\d+).*>/
22
+ PWD = Dir.pwd
23
+
24
+ def to_comment_line
25
+ "# #{file_colon_line}"
26
+ end
27
+
28
+ def backtrace_line(name)
29
+ "#{file_colon_line}:in `#{name}'"
30
+ end
31
+
32
+ if Proc.new{}.to_s =~ PROC_PATTERN
33
+ def file_colon_line
34
+ path, line = *to_s.match(PROC_PATTERN)[1..2]
35
+ path = File.expand_path(path)
36
+ pwd = File.expand_path(PWD)
37
+ pwd.force_encoding(path.encoding)
38
+ if path.index(pwd)
39
+ path = path[pwd.length+1..-1]
40
+ elsif path =~ /.*\/gems\/(.*\.rb)$/
41
+ path = $1
42
+ end
43
+ "#{path}:#{line}"
44
+ end
45
+ else
46
+ STDERR.puts '*** This implementation of Ruby does not report file and line information for procs. ***'
47
+
48
+ def file_colon_line
49
+ 'UNKNOWN:-1'
50
+ end
51
+ end
52
+ end
53
+
54
+ class Object
55
+ def lucid_instance_exec(check_arity, pseudo_method, *args, &block)
56
+ lucid_run_with_backtrace_filtering(pseudo_method) do
57
+ if check_arity && !lucid_compatible_arity?(args, block)
58
+ instance_exec do
59
+ ari = block.arity
60
+ ari = ari < 0 ? (ari.abs-1).to_s + '+' : ari
61
+ s1 = ari == 1 ? '' : 's'
62
+ s2 = args.length == 1 ? '' : 's'
63
+ raise Lucid::ArityMismatchError.new(
64
+ "Your block takes #{ari} argument#{s1}, but the expression matched #{args.length} argument#{s2}."
65
+ )
66
+ end
67
+ else
68
+ instance_exec(*args, &block)
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def lucid_compatible_arity?(args, block)
76
+ return true if block.arity == args.length
77
+ if block.arity < 0
78
+ return true if args.length >= (block.arity.abs - 1)
79
+ end
80
+ false
81
+ end
82
+
83
+ def lucid_run_with_backtrace_filtering(pseudo_method)
84
+ begin
85
+ yield
86
+ rescue Exception => e
87
+ instance_exec_invocation_line = "#{__FILE__}:#{__LINE__ - 2}:in `lucid_run_with_backtrace_filtering'"
88
+ replace_instance_exec_invocation_line!((e.backtrace || []), instance_exec_invocation_line, pseudo_method)
89
+ raise e
90
+ end
91
+ end
92
+
93
+ INSTANCE_EXEC_OFFSET = (Lucid::RUBY_2_0 || Lucid::RUBY_1_9 || Lucid::JRUBY) ? -3 : -4
94
+
95
+ def replace_instance_exec_invocation_line!(backtrace, instance_exec_invocation_line, pseudo_method)
96
+ return if Lucid.use_full_backtrace
97
+
98
+ instance_exec_pos = backtrace.index(instance_exec_invocation_line)
99
+ if instance_exec_pos
100
+ replacement_line = instance_exec_pos + INSTANCE_EXEC_OFFSET
101
+ backtrace[replacement_line].gsub!(/`.*'/, "`#{pseudo_method}'") if pseudo_method
102
+
103
+ depth = backtrace.count { |line| line == instance_exec_invocation_line }
104
+ end_pos = depth > 1 ? instance_exec_pos : -1
105
+
106
+ backtrace[replacement_line+1..end_pos] = nil
107
+ backtrace.compact!
108
+ else
109
+ # Not sure what should happen here.
110
+ end
111
+ end
112
+ end
@@ -1,11 +1,9 @@
1
1
  require 'lucid/factory'
2
2
  require 'lucid/ast/multiline_argument'
3
- require 'lucid/runtime/facade'
3
+ require 'lucid/facade'
4
4
 
5
5
  module Lucid
6
-
7
- class Runtime
8
-
6
+ class ContextLoader
9
7
  class Orchestrator
10
8
 
11
9
  require 'forwardable'
@@ -20,7 +18,7 @@ module Lucid
20
18
  end
21
19
 
22
20
  def step(step)
23
- @orchestrator.invoke(step.name, AST::MultilineArgument.from(step.doc_string || step.rows))
21
+ @orchestrator.invoke(step.name, Lucid::AST::MultilineArgument.from(step.doc_string || step.rows))
24
22
  end
25
23
 
26
24
  def eof
@@ -29,16 +27,16 @@ module Lucid
29
27
 
30
28
  include Factory
31
29
 
32
- def initialize(user_interface, configuration={})
33
- @configuration = Configuration.parse(configuration)
34
- @runtime_facade = Runtime::Facade.new(self, user_interface)
30
+ def initialize(user_interface, context={})
31
+ @context = Context.parse(context)
32
+ @runtime_facade = ContextLoader::Facade.new(self, user_interface)
35
33
  @unsupported_languages = []
36
34
  @supported_languages = []
37
35
  @language_map = {}
38
36
  end
39
37
 
40
- def configure(new_configuration)
41
- @configuration = Configuration.parse(new_configuration)
38
+ def configure(new_context)
39
+ @context = Context.parse(new_context)
42
40
  end
43
41
 
44
42
  # Invokes a series of steps +steps_text+. Example:
@@ -66,19 +64,24 @@ module Lucid
66
64
  # The orchestrator will register the the code language and load up an
67
65
  # implementation of that language. There is a provision to make sure
68
66
  # that the language is not already registered.
69
- def load_code_language(code)
70
- return @language_map[code] if @language_map[code]
71
- lucid_language = create_object_of("Lucid::Interface#{code.capitalize}::#{code.capitalize}Language")
67
+ #
68
+ # @param type [String] the type of file, passed in as an extension value
69
+ # @return [Object] language class
70
+ def load_code_language(type)
71
+ return @language_map[type] if @language_map[type]
72
+ lucid_language = create_object_of("Lucid::Interface#{type.capitalize}::#{type.capitalize}Language")
72
73
  language = lucid_language.new(@runtime_facade)
73
74
  @supported_languages << language
74
- @language_map[code] = language
75
+ @language_map[type] = language
75
76
  language
76
77
  end
77
78
 
78
79
  # The orchestrator will load only the loadable execution context files.
79
80
  # This is how the orchestrator will, quite literally, orchestrate the
80
81
  # execution of specs with the code logic that supports those specs.
81
- # @see Lucid::Runtime.load_execution_context
82
+ #
83
+ # @param files [Array] all files gathering for the execution context
84
+ # @see Lucid::ContextLoader.load_execution_context
82
85
  def load_files(files)
83
86
  log.info("Orchestrator Load Files:\n")
84
87
  files.each do |file|
@@ -98,10 +101,10 @@ module Lucid
98
101
  end.flatten
99
102
  end
100
103
 
101
- def matcher_text(step_keyword, step_name, multiline_arg_class) #:nodoc:
104
+ def matcher_text(step_keyword, step_name, multiline_arg_class)
102
105
  load_code_language('rb') if unknown_programming_language?
103
106
  @supported_languages.map do |programming_language|
104
- programming_language.matcher_text(step_keyword, step_name, multiline_arg_class, @configuration.matcher_type)
107
+ programming_language.matcher_text(step_keyword, step_name, multiline_arg_class, @context.matcher_type)
105
108
  end.join("\n")
106
109
  end
107
110
 
@@ -131,7 +134,7 @@ module Lucid
131
134
  end.flatten
132
135
  end
133
136
 
134
- def step_match(step_name, name_to_report=nil) #:nodoc:
137
+ def step_match(step_name, name_to_report=nil)
135
138
  @match_cache ||= {}
136
139
 
137
140
  match = @match_cache[[step_name, name_to_report]]
@@ -151,7 +154,7 @@ module Lucid
151
154
  end
152
155
 
153
156
  def guess_step_matches?
154
- @configuration.guess?
157
+ @context.guess?
155
158
  end
156
159
 
157
160
  def matches(step_name, name_to_report)
@@ -160,7 +163,7 @@ module Lucid
160
163
  end.flatten
161
164
  end
162
165
 
163
- def best_matches(step_name, step_matches) #:nodoc:
166
+ def best_matches(step_name, step_matches)
164
167
  no_groups = step_matches.select {|step_match| step_match.args.length == 0}
165
168
  max_arg_length = step_matches.map {|step_match| step_match.args.length }.max
166
169
  top_groups = step_matches.select {|step_match| step_match.args.length == max_arg_length }
@@ -178,12 +181,16 @@ module Lucid
178
181
 
179
182
  # For each execution context file, the orchestrator will determine the
180
183
  # code language associated with the file.
184
+ #
185
+ # @param file [String] relative path/file reference from the spec repo
181
186
  def load_file(file)
182
- if language = get_language_for(file)
187
+ language = get_language_for(file)
188
+
189
+ if language.nil?
190
+ log.info(" * #{file} [NOT SUPPORTED]\n")
191
+ else
183
192
  log.info(" * #{file}\n")
184
193
  language.load_code_file(file)
185
- else
186
- log.info(" * #{file} [NOT SUPPORTED]\n")
187
194
  end
188
195
  end
189
196
 
@@ -197,8 +204,13 @@ module Lucid
197
204
  # of a supported language. If an object is returned it will be an
198
205
  # object of this sort:
199
206
  # Lucid::InterfaceRb::RbLanguage
207
+ #
208
+ # @param file [String] relative path/file reference from the spec repo
209
+ # @return [nil or class] full class reference if found, nil otherwise
200
210
  def get_language_for(file)
201
- if extension = File.extname(file)[1..-1]
211
+ extension = File.extname(file)[1..-1]
212
+
213
+ if extension
202
214
  return nil if @unsupported_languages.index(extension)
203
215
  begin
204
216
  load_code_language(extension)
@@ -2,7 +2,7 @@ require 'rbconfig'
2
2
 
3
3
  module Lucid
4
4
  unless defined?(Lucid::VERSION)
5
- VERSION = '0.3.3'
5
+ VERSION = '0.4.0'
6
6
  BINARY = File.expand_path(File.dirname(__FILE__) + '/../../bin/lucid')
7
7
  LIBDIR = File.expand_path(File.dirname(__FILE__) + '/../../lib')
8
8
  JRUBY = defined?(JRUBY_VERSION)
@@ -1,18 +1,18 @@
1
1
  module Lucid
2
- class Runtime
2
+ class ContextLoader
3
3
 
4
4
  class Results
5
- def initialize(configuration)
6
- @configuration = configuration
5
+ def initialize(context)
6
+ @context = context
7
7
  @inserted_steps = {}
8
8
  @inserted_scenarios = {}
9
9
  end
10
10
 
11
- def configure(new_configuration)
12
- @configuration = Configuration.parse(new_configuration)
11
+ def configure(new_context)
12
+ @context = Context.parse(new_context)
13
13
  end
14
14
 
15
- def step_visited(step) #:nodoc:
15
+ def step_visited(step)
16
16
  step_id = step.object_id
17
17
 
18
18
  unless @inserted_steps.has_key?(step_id)
@@ -21,7 +21,7 @@ module Lucid
21
21
  end
22
22
  end
23
23
 
24
- def scenario_visited(scenario) #:nodoc:
24
+ def scenario_visited(scenario)
25
25
  scenario_id = scenario.object_id
26
26
 
27
27
  unless @inserted_scenarios.has_key?(scenario_id)
@@ -39,7 +39,7 @@ module Lucid
39
39
  end
40
40
  end
41
41
 
42
- def scenarios(status = nil) #:nodoc:
42
+ def scenarios(status = nil)
43
43
  @scenarios ||= []
44
44
  if(status)
45
45
  @scenarios.select{|scenario| scenario.status == status}
@@ -49,11 +49,11 @@ module Lucid
49
49
  end
50
50
 
51
51
  def failure?
52
- if @configuration.wip?
52
+ if @context.wip?
53
53
  scenarios(:passed).any?
54
54
  else
55
55
  scenarios(:failed).any? || steps(:failed).any? ||
56
- (@configuration.strict? && (steps(:undefined).any? || steps(:pending).any?))
56
+ (@context.strict? && (steps(:undefined).any? || steps(:pending).any?))
57
57
  end
58
58
  end
59
59
  end