lucid 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +30 -10
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +15 -0
- data/Gemfile +4 -2
- data/HISTORY.md +22 -0
- data/{LICENSE.txt → LICENSE} +6 -3
- data/README.md +22 -8
- data/Rakefile +2 -1
- data/bin/lucid +10 -10
- data/bin/lucid-gen +4 -0
- data/lib/autotest/discover.rb +11 -0
- data/lib/autotest/lucid.rb +6 -0
- data/lib/autotest/lucid_mixin.rb +135 -0
- data/lib/autotest/lucid_rails.rb +6 -0
- data/lib/autotest/lucid_rails_rspec.rb +6 -0
- data/lib/autotest/lucid_rails_rspec2.rb +6 -0
- data/lib/autotest/lucid_rspec.rb +6 -0
- data/lib/autotest/lucid_rspec2.rb +6 -0
- data/lib/lucid.rb +32 -1
- data/lib/lucid/ast.rb +20 -0
- data/lib/lucid/ast/background.rb +116 -0
- data/lib/lucid/ast/comment.rb +24 -0
- data/lib/lucid/ast/doc_string.rb +44 -0
- data/lib/lucid/ast/empty_background.rb +33 -0
- data/lib/lucid/ast/examples.rb +49 -0
- data/lib/lucid/ast/feature.rb +99 -0
- data/lib/lucid/ast/has_steps.rb +74 -0
- data/lib/lucid/ast/location.rb +41 -0
- data/lib/lucid/ast/multiline_argument.rb +31 -0
- data/lib/lucid/ast/names.rb +13 -0
- data/lib/lucid/ast/outline_table.rb +194 -0
- data/lib/lucid/ast/scenario.rb +103 -0
- data/lib/lucid/ast/scenario_outline.rb +144 -0
- data/lib/lucid/ast/specs.rb +38 -0
- data/lib/lucid/ast/step.rb +122 -0
- data/lib/lucid/ast/step_collection.rb +92 -0
- data/lib/lucid/ast/step_invocation.rb +196 -0
- data/lib/lucid/ast/table.rb +730 -0
- data/lib/lucid/ast/tags.rb +28 -0
- data/lib/lucid/ast/tdl_walker.rb +195 -0
- data/lib/lucid/cli/app.rb +78 -0
- data/lib/lucid/cli/configuration.rb +261 -0
- data/lib/lucid/cli/options.rb +463 -0
- data/lib/lucid/cli/profile.rb +101 -0
- data/lib/lucid/configuration.rb +53 -0
- data/lib/lucid/core_ext/disable_autorunners.rb +15 -0
- data/lib/lucid/core_ext/instance_exec.rb +70 -0
- data/lib/lucid/core_ext/proc.rb +36 -0
- data/lib/lucid/core_ext/string.rb +9 -0
- data/lib/lucid/errors.rb +40 -0
- data/lib/lucid/factory.rb +43 -0
- data/lib/lucid/formatter/ansicolor.rb +168 -0
- data/lib/lucid/formatter/console.rb +218 -0
- data/lib/lucid/formatter/debug.rb +33 -0
- data/lib/lucid/formatter/duration.rb +11 -0
- data/lib/lucid/formatter/gherkin_formatter_adapter.rb +94 -0
- data/lib/lucid/formatter/gpretty.rb +24 -0
- data/lib/lucid/formatter/html.rb +610 -0
- data/lib/lucid/formatter/interceptor.rb +66 -0
- data/lib/lucid/formatter/io.rb +31 -0
- data/lib/lucid/formatter/jquery-min.js +154 -0
- data/lib/lucid/formatter/json.rb +19 -0
- data/lib/lucid/formatter/json_pretty.rb +10 -0
- data/lib/lucid/formatter/junit.rb +177 -0
- data/lib/lucid/formatter/lucid.css +283 -0
- data/lib/lucid/formatter/lucid.sass +244 -0
- data/lib/lucid/formatter/ordered_xml_markup.rb +24 -0
- data/lib/lucid/formatter/progress.rb +95 -0
- data/lib/lucid/formatter/rerun.rb +91 -0
- data/lib/lucid/formatter/standard.rb +235 -0
- data/lib/lucid/formatter/stepdefs.rb +14 -0
- data/lib/lucid/formatter/steps.rb +49 -0
- data/lib/lucid/formatter/summary.rb +35 -0
- data/lib/lucid/formatter/unicode.rb +53 -0
- data/lib/lucid/formatter/usage.rb +132 -0
- data/lib/lucid/generator.rb +21 -0
- data/lib/lucid/generators/project.rb +70 -0
- data/lib/lucid/generators/project/Gemfile.tt +6 -0
- data/lib/lucid/generators/project/browser-symbiont.rb +24 -0
- data/lib/lucid/generators/project/driver-symbiont.rb +4 -0
- data/lib/lucid/generators/project/errors.rb +26 -0
- data/lib/lucid/generators/project/events-symbiont.rb +36 -0
- data/lib/lucid/generators/project/lucid-symbiont.yml +6 -0
- data/lib/lucid/interface.rb +8 -0
- data/lib/lucid/interface_methods.rb +125 -0
- data/lib/lucid/interface_rb/matcher.rb +108 -0
- data/lib/lucid/interface_rb/rb_hook.rb +18 -0
- data/lib/lucid/interface_rb/rb_language.rb +190 -0
- data/lib/lucid/interface_rb/rb_lucid.rb +119 -0
- data/lib/lucid/interface_rb/rb_step_definition.rb +122 -0
- data/lib/lucid/interface_rb/rb_transform.rb +57 -0
- data/lib/lucid/interface_rb/rb_world.rb +136 -0
- data/lib/lucid/interface_rb/regexp_argument_matcher.rb +21 -0
- data/lib/lucid/load_path.rb +13 -0
- data/lib/lucid/parser.rb +2 -126
- data/lib/lucid/platform.rb +27 -0
- data/lib/lucid/rspec/allow_doubles.rb +20 -0
- data/lib/lucid/rspec/disallow_options.rb +27 -0
- data/lib/lucid/runtime.rb +200 -0
- data/lib/lucid/runtime/facade.rb +60 -0
- data/lib/lucid/runtime/interface_io.rb +60 -0
- data/lib/lucid/runtime/orchestrator.rb +218 -0
- data/lib/lucid/runtime/results.rb +64 -0
- data/lib/lucid/runtime/specs_loader.rb +79 -0
- data/lib/lucid/spec_file.rb +112 -0
- data/lib/lucid/step_definition_light.rb +20 -0
- data/lib/lucid/step_definitions.rb +13 -0
- data/lib/lucid/step_match.rb +99 -0
- data/lib/lucid/tdl_builder.rb +282 -0
- data/lib/lucid/term/ansicolor.rb +118 -0
- data/lib/lucid/unit.rb +11 -0
- data/lib/lucid/wire_support/configuration.rb +38 -0
- data/lib/lucid/wire_support/connection.rb +61 -0
- data/lib/lucid/wire_support/request_handler.rb +32 -0
- data/lib/lucid/wire_support/wire_exception.rb +32 -0
- data/lib/lucid/wire_support/wire_language.rb +54 -0
- data/lib/lucid/wire_support/wire_packet.rb +34 -0
- data/lib/lucid/wire_support/wire_protocol.rb +43 -0
- data/lib/lucid/wire_support/wire_protocol/requests.rb +125 -0
- data/lib/lucid/wire_support/wire_step_definition.rb +26 -0
- data/lucid.gemspec +25 -14
- metadata +220 -12
- data/lib/lucid/app.rb +0 -103
- data/lib/lucid/options.rb +0 -168
- data/lib/lucid/version.rb +0 -3
- data/lucid.yml +0 -8
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'gherkin/tag_expression'
|
2
|
+
|
3
|
+
module Lucid
|
4
|
+
module AST
|
5
|
+
class Tags #:nodoc:
|
6
|
+
attr_reader :tags
|
7
|
+
|
8
|
+
def initialize(line, tags)
|
9
|
+
@line, @tags = line, tags
|
10
|
+
end
|
11
|
+
|
12
|
+
def accept(visitor)
|
13
|
+
return if Lucid.wants_to_quit
|
14
|
+
@tags.each do |tag|
|
15
|
+
visitor.visit_tag_name(tag.name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def accept_hook?(hook)
|
20
|
+
Gherkin::TagExpression.new(hook.tag_expressions).evaluate(@tags)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_sexp
|
24
|
+
@tags.map{|tag| [:tag, tag.name]}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
module Lucid
|
2
|
+
module AST
|
3
|
+
class TDLWalker
|
4
|
+
attr_accessor :configuration #:nodoc:
|
5
|
+
attr_reader :runtime #:nodoc:
|
6
|
+
|
7
|
+
def initialize(runtime, listeners = [], configuration = Lucid::Configuration.default)
|
8
|
+
@runtime, @listeners, @configuration = runtime, listeners, configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute(scenario, skip_hooks)
|
12
|
+
runtime.with_hooks(scenario, skip_hooks) do
|
13
|
+
scenario.skip_invoke! if scenario.failed?
|
14
|
+
visit_steps(scenario.steps)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# The ability to visit specs is the first step in turning a spec into
|
19
|
+
# what is traditionally called a feature. The spec file and the feature
|
20
|
+
# are initially the same concept. When the spec is visited, the high
|
21
|
+
# level construct (feature, ability) is determined.
|
22
|
+
# @see Lucid::Runtime.run
|
23
|
+
def visit_features(features)
|
24
|
+
broadcast(features) do
|
25
|
+
features.accept(self)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def visit_feature(feature)
|
30
|
+
broadcast(feature) do
|
31
|
+
feature.accept(self)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def visit_comment(comment)
|
36
|
+
broadcast(comment) do
|
37
|
+
comment.accept(self)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def visit_comment_line(comment_line)
|
42
|
+
broadcast(comment_line)
|
43
|
+
end
|
44
|
+
|
45
|
+
def visit_tags(tags)
|
46
|
+
broadcast(tags) do
|
47
|
+
tags.accept(self)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def visit_tag_name(tag_name)
|
52
|
+
broadcast(tag_name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def visit_feature_name(keyword, name)
|
56
|
+
broadcast(keyword, name)
|
57
|
+
end
|
58
|
+
|
59
|
+
# +feature_element+ is either Scenario or ScenarioOutline
|
60
|
+
def visit_feature_element(feature_element)
|
61
|
+
broadcast(feature_element) do
|
62
|
+
feature_element.accept(self)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def visit_background(background)
|
67
|
+
broadcast(background) do
|
68
|
+
background.accept(self)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def visit_background_name(keyword, name, file_colon_line, source_indent)
|
73
|
+
broadcast(keyword, name, file_colon_line, source_indent)
|
74
|
+
end
|
75
|
+
|
76
|
+
def visit_examples_array(examples_array)
|
77
|
+
broadcast(examples_array) do
|
78
|
+
examples_array.accept(self)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def visit_examples(examples)
|
83
|
+
broadcast(examples) do
|
84
|
+
examples.accept(self)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def visit_examples_name(keyword, name)
|
89
|
+
broadcast(keyword, name)
|
90
|
+
end
|
91
|
+
|
92
|
+
def visit_outline_table(outline_table)
|
93
|
+
broadcast(outline_table) do
|
94
|
+
outline_table.accept(self)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def visit_scenario_name(keyword, name, file_colon_line, source_indent)
|
99
|
+
broadcast(keyword, name, file_colon_line, source_indent)
|
100
|
+
end
|
101
|
+
|
102
|
+
def visit_steps(steps)
|
103
|
+
broadcast(steps) do
|
104
|
+
steps.accept(self)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def visit_step(step)
|
109
|
+
broadcast(step) do
|
110
|
+
step.accept(self)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def visit_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
|
115
|
+
broadcast(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line) do
|
116
|
+
visit_step_name(keyword, step_match, status, source_indent, background, file_colon_line)
|
117
|
+
visit_multiline_arg(multiline_arg) if multiline_arg
|
118
|
+
visit_exception(exception, status) if exception
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def visit_step_name(keyword, step_match, status, source_indent, background, file_colon_line) #:nodoc:
|
123
|
+
broadcast(keyword, step_match, status, source_indent, background, file_colon_line)
|
124
|
+
end
|
125
|
+
|
126
|
+
def visit_multiline_arg(multiline_arg) #:nodoc:
|
127
|
+
broadcast(multiline_arg) do
|
128
|
+
multiline_arg.accept(self)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def visit_exception(exception, status) #:nodoc:
|
133
|
+
broadcast(exception, status)
|
134
|
+
end
|
135
|
+
|
136
|
+
def visit_doc_string(string)
|
137
|
+
broadcast(string)
|
138
|
+
end
|
139
|
+
|
140
|
+
def visit_table_row(table_row)
|
141
|
+
broadcast(table_row) do
|
142
|
+
table_row.accept(self)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def visit_table_cell(table_cell)
|
147
|
+
broadcast(table_cell) do
|
148
|
+
table_cell.accept(self)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def visit_table_cell_value(value, status)
|
153
|
+
broadcast(value, status)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Print +messages+. This method can be called from within StepDefinitions.
|
157
|
+
def puts(*messages)
|
158
|
+
broadcast(*messages)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Embed +file+ of +mime_type+ in the formatter. This method can be called from within StepDefinitions.
|
162
|
+
# For most formatters this is a no-op.
|
163
|
+
def embed(file, mime_type, label)
|
164
|
+
broadcast(file, mime_type, label)
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
def broadcast(*args, &block)
|
170
|
+
message = extract_method_name_from(caller)
|
171
|
+
message.gsub!('visit_', '')
|
172
|
+
if block_given?
|
173
|
+
send_to_all("before_#{message}", *args)
|
174
|
+
yield if block_given?
|
175
|
+
send_to_all("after_#{message}", *args)
|
176
|
+
else
|
177
|
+
send_to_all(message, *args)
|
178
|
+
end
|
179
|
+
self
|
180
|
+
end
|
181
|
+
|
182
|
+
def send_to_all(message, *args)
|
183
|
+
@listeners.each do |listener|
|
184
|
+
if listener.respond_to?(message)
|
185
|
+
listener.__send__(message, *args)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
def extract_method_name_from(call_stack)
|
190
|
+
call_stack[0].match(/in `(.*)'/).captures[0]
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'gherkin'
|
2
|
+
require 'optparse'
|
3
|
+
require 'lucid'
|
4
|
+
require 'logger'
|
5
|
+
require 'lucid/parser'
|
6
|
+
require 'lucid/spec_file'
|
7
|
+
require 'lucid/cli/configuration'
|
8
|
+
|
9
|
+
module Lucid
|
10
|
+
module CLI
|
11
|
+
class App
|
12
|
+
def initialize(args, stdin=STDIN, out=STDOUT, err=STDERR, kernel=Kernel)
|
13
|
+
raise "args can't be nil" unless args
|
14
|
+
raise "out can't be nil" unless out
|
15
|
+
raise "err can't be nil" unless err
|
16
|
+
raise "kernel can't be nil" unless kernel
|
17
|
+
@args = args
|
18
|
+
@out = out
|
19
|
+
@err = err
|
20
|
+
@kernel = kernel
|
21
|
+
@configuration = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def start(existing_runtime = nil)
|
25
|
+
trap_interrupt
|
26
|
+
|
27
|
+
runtime = if existing_runtime
|
28
|
+
existing_runtime.configure(configuration)
|
29
|
+
existing_runtime
|
30
|
+
else
|
31
|
+
Runtime.new(configuration)
|
32
|
+
end
|
33
|
+
|
34
|
+
log.debug("Runtime: #{runtime.inspect}")
|
35
|
+
|
36
|
+
runtime.run
|
37
|
+
runtime.write_stepdefs_json
|
38
|
+
failure = runtime.results.failure? || Lucid.wants_to_quit
|
39
|
+
@kernel.exit(failure ? 1 : 0)
|
40
|
+
rescue ProfilesNotDefinedError, YmlLoadError, ProfileNotFound => e
|
41
|
+
@err.puts(e.message)
|
42
|
+
rescue SystemExit => e
|
43
|
+
@kernel.exit(e.status)
|
44
|
+
rescue Errno::EACCES, Errno::ENOENT => e
|
45
|
+
@err.puts("#{e.message} (#{e.class})")
|
46
|
+
@kernel.exit(1)
|
47
|
+
rescue Exception => e
|
48
|
+
@err.puts("#{e.message} (#{e.class})")
|
49
|
+
@err.puts(e.backtrace.join("\n"))
|
50
|
+
@kernel.exit(1)
|
51
|
+
end
|
52
|
+
|
53
|
+
def configuration
|
54
|
+
return @configuration if @configuration
|
55
|
+
|
56
|
+
@configuration = Configuration.new(@out, @err)
|
57
|
+
@configuration.parse(@args)
|
58
|
+
Lucid.logger = @configuration.log
|
59
|
+
log.debug("Configuration: #{@configuration.inspect}")
|
60
|
+
@configuration
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def log
|
66
|
+
Lucid.logger
|
67
|
+
end
|
68
|
+
|
69
|
+
def trap_interrupt
|
70
|
+
trap('INT') do
|
71
|
+
exit!(1) if Lucid.wants_to_quit
|
72
|
+
Lucid.wants_to_quit = true
|
73
|
+
STDERR.puts "\nExiting. Interrupt again to exit immediately."
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,261 @@
|
|
1
|
+
require 'lucid/cli/options'
|
2
|
+
require 'lucid/factory'
|
3
|
+
require 'gherkin/tag_expression'
|
4
|
+
|
5
|
+
module Lucid
|
6
|
+
module CLI
|
7
|
+
class YmlLoadError < StandardError; end
|
8
|
+
class ProfilesNotDefinedError < YmlLoadError; end
|
9
|
+
class ProfileNotFound < StandardError; end
|
10
|
+
|
11
|
+
class Configuration
|
12
|
+
include ObjectFactory
|
13
|
+
|
14
|
+
attr_reader :out_stream
|
15
|
+
|
16
|
+
def initialize(out_stream = STDOUT, err_stream = STDERR)
|
17
|
+
@out_stream = out_stream
|
18
|
+
@err_stream = err_stream
|
19
|
+
@options = Options.new(@out_stream, @err_stream, :default_profile => 'default')
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(args)
|
23
|
+
@args = args
|
24
|
+
@options.parse(args)
|
25
|
+
log.debug("Options: #{@options.inspect}")
|
26
|
+
|
27
|
+
prepare_output_formatting
|
28
|
+
raise("You cannot use both --strict and --wip tags.") if strict? && wip?
|
29
|
+
|
30
|
+
@options[:tag_expression] = Gherkin::TagExpression.new(@options[:tag_expressions])
|
31
|
+
|
32
|
+
set_environment_variables
|
33
|
+
end
|
34
|
+
|
35
|
+
def verbose?
|
36
|
+
@options[:verbose]
|
37
|
+
end
|
38
|
+
|
39
|
+
def debug?
|
40
|
+
@options[:debug]
|
41
|
+
end
|
42
|
+
|
43
|
+
def strict?
|
44
|
+
@options[:strict]
|
45
|
+
end
|
46
|
+
|
47
|
+
def wip?
|
48
|
+
@options[:wip]
|
49
|
+
end
|
50
|
+
|
51
|
+
def guess?
|
52
|
+
@options[:guess]
|
53
|
+
end
|
54
|
+
|
55
|
+
def dry_run?
|
56
|
+
@options[:dry_run]
|
57
|
+
end
|
58
|
+
|
59
|
+
def expand?
|
60
|
+
@options[:expand]
|
61
|
+
end
|
62
|
+
|
63
|
+
def testdefs
|
64
|
+
@options[:testdefs]
|
65
|
+
end
|
66
|
+
|
67
|
+
def matcher_type
|
68
|
+
@options[:matcher_type] || :regexp
|
69
|
+
end
|
70
|
+
|
71
|
+
def establish_tdl_walker(runtime)
|
72
|
+
AST::TDLWalker.new(runtime, formatters(runtime), self)
|
73
|
+
end
|
74
|
+
|
75
|
+
def formatter_class(name)
|
76
|
+
if(lucid_format = Options::LUCID_FORMATS[name])
|
77
|
+
create_object_of(lucid_format[0])
|
78
|
+
else
|
79
|
+
create_object_of(name)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# The spec_repo is used to get all of the files that are in the
|
84
|
+
# "spec source" location. This location defaults to 'specs' but can
|
85
|
+
# be changed via a command line option. The spec repo will remove
|
86
|
+
# any directory names and, perhaps counter-intuitively, any spec
|
87
|
+
# files. The reason for this is that, by default, the "spec repo"
|
88
|
+
# contains everything that Lucid will need, whether that be
|
89
|
+
# test spec files or code files to support them.
|
90
|
+
def spec_repo
|
91
|
+
requires = @options[:require].empty? ? require_dirs : @options[:require]
|
92
|
+
|
93
|
+
files = requires.map do |path|
|
94
|
+
path = path.gsub(/\\/, '/') # convert \ to /
|
95
|
+
path = path.gsub(/\/$/, '') # removing trailing /
|
96
|
+
File.directory?(path) ? Dir["#{path}/**/*"] : path
|
97
|
+
end.flatten.uniq
|
98
|
+
|
99
|
+
extract_excluded_files(files)
|
100
|
+
|
101
|
+
files.reject! {|f| !File.file?(f)}
|
102
|
+
files.reject! {|f| File.extname(f) == ".#{spec_type}" }
|
103
|
+
files.reject! {|f| f =~ /^http/}
|
104
|
+
files.sort
|
105
|
+
end
|
106
|
+
|
107
|
+
# The definition context refers to any files that are found in the spec
|
108
|
+
# repository that are not spec files and that are not contained in the
|
109
|
+
# library path.
|
110
|
+
# @see Lucid::Runtime.load_execution_context
|
111
|
+
def definition_context
|
112
|
+
spec_repo.reject { |f| f=~ %r{/#{library_path}/} }
|
113
|
+
end
|
114
|
+
|
115
|
+
# The library context will store an array of all files that are found
|
116
|
+
# in the library_path. This path defaults to 'lucid' but can be changed
|
117
|
+
# via a command line option.
|
118
|
+
# @see Lucid::Runtime.load_execution_context
|
119
|
+
def library_context
|
120
|
+
library_files = spec_repo.select { |f| f =~ %r{/#{library_path}/} }
|
121
|
+
driver_file = library_files.select {|f| f =~ %r{/#{library_path}/driver\..*} }
|
122
|
+
non_driver_files = library_files - driver_file
|
123
|
+
|
124
|
+
@options[:dry_run] ? non_driver_files : driver_file + non_driver_files
|
125
|
+
end
|
126
|
+
|
127
|
+
# The spec files refer to any files found within the spec repository
|
128
|
+
# that match the specification file type. Note that this method is
|
129
|
+
# called from the specs action in a Runtime instance.
|
130
|
+
# @see Lucid::Runtime.specs
|
131
|
+
def spec_files
|
132
|
+
files = with_default_specs_path(spec_source).map do |path|
|
133
|
+
path = path.gsub(/\\/, '/') # convert \ to /
|
134
|
+
path = path.chomp('/') # removing trailing /
|
135
|
+
if File.directory?(path)
|
136
|
+
Dir["#{path}/**/*.#{spec_type}"].sort
|
137
|
+
elsif path[0..0] == '@' and # @listfile.txt
|
138
|
+
File.file?(path[1..-1]) # listfile.txt is a file
|
139
|
+
IO.read(path[1..-1]).split
|
140
|
+
else
|
141
|
+
path
|
142
|
+
end
|
143
|
+
end.flatten.uniq
|
144
|
+
|
145
|
+
log.info("Spec Files: #{files}")
|
146
|
+
|
147
|
+
extract_excluded_files(files)
|
148
|
+
files
|
149
|
+
end
|
150
|
+
|
151
|
+
# A call to spec_location will return the location of a spec repository.
|
152
|
+
def spec_location
|
153
|
+
dirs = spec_source.map { |f| File.directory?(f) ? f : File.dirname(f) }.uniq
|
154
|
+
dirs.delete('.') unless spec_source.include?('.')
|
155
|
+
|
156
|
+
with_default_specs_path(dirs)
|
157
|
+
end
|
158
|
+
|
159
|
+
# The "spec_type" refers to the file type (or extension) of spec files.
|
160
|
+
# This is how Lucid will recognize the files that should be treated as
|
161
|
+
# specs within a spec repository.
|
162
|
+
def spec_type
|
163
|
+
@options[:spec_type].empty? ? 'spec' : @options[:spec_type]
|
164
|
+
end
|
165
|
+
|
166
|
+
# The "library_path" refers to the location within the spec repository
|
167
|
+
# that holds the logic that supports the basic operations of the
|
168
|
+
# execution. This value will default to 'lucid' but the value of
|
169
|
+
# library_path can be changed via a command line option.
|
170
|
+
def library_path
|
171
|
+
@options[:library_path].empty? ? 'lucid' : @options[:library_path]
|
172
|
+
end
|
173
|
+
|
174
|
+
def log
|
175
|
+
logger = Logger.new(@out_stream)
|
176
|
+
logger.formatter = LogFormatter.new
|
177
|
+
logger.level = Logger::WARN
|
178
|
+
logger.level = Logger::INFO if self.verbose?
|
179
|
+
logger.level = Logger::DEBUG if self.debug?
|
180
|
+
logger
|
181
|
+
end
|
182
|
+
|
183
|
+
def tag_expression
|
184
|
+
Gherkin::TagExpression.new(@options[:tag_expressions])
|
185
|
+
end
|
186
|
+
|
187
|
+
def filters
|
188
|
+
@options.filters
|
189
|
+
end
|
190
|
+
|
191
|
+
def formats
|
192
|
+
@options[:formats]
|
193
|
+
end
|
194
|
+
|
195
|
+
# The "spec_source" refers to the location of the spec repository. This
|
196
|
+
# value will default to 'specs' but the value of spec_source can be
|
197
|
+
# changed if a repository location is specified on the command line when
|
198
|
+
# calling Lucid.
|
199
|
+
def spec_source
|
200
|
+
@options[:spec_source]
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
204
|
+
|
205
|
+
def with_default_specs_path(paths)
|
206
|
+
return ['specs'] if paths.empty?
|
207
|
+
paths
|
208
|
+
end
|
209
|
+
|
210
|
+
def formatters(runtime)
|
211
|
+
# TODO: Remove the autoformat functionality; use the Gherkin CLI instead.
|
212
|
+
if @options[:autoformat]
|
213
|
+
require 'lucid/formatter/standard'
|
214
|
+
return [Formatter::Standard.new(runtime, nil, @options)]
|
215
|
+
end
|
216
|
+
|
217
|
+
@options[:formats].map do |format|
|
218
|
+
# The name will be a name, like 'standard'. The route will be the
|
219
|
+
# location where output is sent to, such as 'STDOUT'.
|
220
|
+
name = format[0]
|
221
|
+
route = format[1]
|
222
|
+
begin
|
223
|
+
formatter = formatter_class(name)
|
224
|
+
formatter.new(runtime, route, @options)
|
225
|
+
rescue Exception => e
|
226
|
+
e.message << "\nLucid is unable to create the formatter: #{name}"
|
227
|
+
raise e
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def set_environment_variables
|
233
|
+
@options[:env_vars].each do |var, value|
|
234
|
+
ENV[var] = value
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def prepare_output_formatting
|
239
|
+
@options[:formats] << ['standard', @out_stream] if @options[:formats].empty?
|
240
|
+
@options[:formats] = @options[:formats].sort_by{|f| f[1] == @out_stream ? -1 : 1}
|
241
|
+
@options[:formats].uniq!
|
242
|
+
|
243
|
+
streams = @options[:formats].map { |(_, stream)| stream }
|
244
|
+
|
245
|
+
if streams != streams.uniq
|
246
|
+
raise "All but one formatter must use --out, only one can print to each stream (or STDOUT)"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def extract_excluded_files(files)
|
251
|
+
files.reject! {|path| @options[:excludes].detect {|pattern| path =~ pattern } }
|
252
|
+
end
|
253
|
+
|
254
|
+
def require_dirs
|
255
|
+
spec_location + Dir['vendor/{gems,plugins}/*/lucid']
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
end
|