cuketagger 1.5 → 1.6.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +13 -0
- data/Gemfile +18 -0
- data/History.md +11 -0
- data/LICENSE.txt +23 -0
- data/README.markdown +60 -8
- data/Rakefile +21 -55
- data/bin/cuketagger +5 -5
- data/cuketagger.gemspec +31 -0
- data/lib/cuketagger.rb +13 -18
- data/lib/cuketagger/array_list_extension.rb +13 -13
- data/lib/cuketagger/tagger.rb +231 -130
- data/lib/cuketagger/version.rb +3 -3
- data/testing/cucumber/features/.cucumber/stepdefs.json +146 -0
- data/testing/cucumber/features/cuketagger.feature +173 -0
- data/testing/cucumber/features/scenario_outline.feature +37 -0
- data/testing/cucumber/features/step_definitions/cuketagger_steps.rb +20 -0
- data/testing/cucumber/features/support/env.rb +11 -0
- data/testing/cuke_tagger_helper.rb +31 -0
- data/testing/rspec/spec/spec_helper.rb +27 -0
- data/testing/rspec/spec/tagger_integration_spec.rb +1548 -0
- data/testing/rspec/spec/tagger_unit_spec.rb +23 -0
- metadata +147 -64
- data/lib/cuketagger/tag_formatter.rb +0 -21
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: aca5d51f29ef842db370f4ebcfdf6637c1b04d84
|
4
|
+
data.tar.gz: 8a654ad26ef3eb1f9d516d192061c12a9c1c2ad5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 455c33a05e17c3ade2dbcec02fab34d1a04152580ce2bd3fbed451eee5908ae1b0d637824e261bda2d3953e1de3719875cf7fe52a8f061cd43aae53a17c28f76
|
7
|
+
data.tar.gz: 06be308f0f01bf9cf1be6b076e0594e5d13b1afaa436e865262effcd447f547e02e35e6a8ad6a8e024e32bf2614de76e5ae7e7b6a49cb8b7830fa88a53bbbefb
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.8.7
|
4
|
+
- 1.9.3
|
5
|
+
- 2.0.0
|
6
|
+
- 2.1.6
|
7
|
+
- 2.2.2
|
8
|
+
|
9
|
+
# todo - Remove this once TravisCI fixes their bundler issue (https://github.com/alphagov/govuk_template/pull/186)
|
10
|
+
before_install:
|
11
|
+
- gem install bundler -v 1.9.10
|
12
|
+
|
13
|
+
script: bundle exec rake cuketagger:ci_build
|
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in cuketagger.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
if RUBY_VERSION =~ /^1\.8/
|
7
|
+
gem 'cucumber', '<1.3.0'
|
8
|
+
gem 'gherkin', '<2.12.0'
|
9
|
+
gem 'rake', '< 11.0' # Rake dropped 1.8.x support after this version
|
10
|
+
elsif RUBY_VERSION =~ /^1\./
|
11
|
+
gem 'cucumber', '<2.0.0'
|
12
|
+
end
|
13
|
+
|
14
|
+
if RUBY_VERSION =~ /^1\./
|
15
|
+
gem 'tins', '< 1.7' # The 'tins' gem requires Ruby 2.x on/after this version
|
16
|
+
gem 'json', '< 2.0' # The 'json' gem drops pre-Ruby 2.x support on/after this version
|
17
|
+
gem 'term-ansicolor', '< 1.4' # The 'term-ansicolor' gem requires Ruby 2.x on/after this version
|
18
|
+
end
|
data/History.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
### Version 1.6.0 / 2016-12-11
|
2
|
+
|
3
|
+
* Updated the dependencies used by the gem in order to be compatible with current
|
4
|
+
libraries.
|
5
|
+
* File modification has been minimized. Only the lines of a file that are affected
|
6
|
+
by tagging are modified. Previously, the entire file was potentially reformatted.
|
7
|
+
|
8
|
+
|
9
|
+
### Version 1.5.0 / 2011-04-17
|
10
|
+
|
11
|
+
* The Great Before Times...
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009-2012 Jari Bakken
|
4
|
+
Copyright (c) 2015 Eric Kessler
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
CHANGED
@@ -1,8 +1,60 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
[](https://rubygems.org/gems/cuketagger)
|
2
|
+
[](https://travis-ci.org/enkessler/cuketagger)
|
3
|
+
[](https://gemnasium.com/enkessler/cuketagger)
|
4
|
+
|
5
|
+
|
6
|
+
# Cuketagger
|
7
|
+
|
8
|
+
This gem provides the ability to manipulate, in bulk, the tags in a Cucumber test
|
9
|
+
suite.
|
10
|
+
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
gem 'cuketagger'
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install cuketagger
|
25
|
+
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
Tags can be added,
|
30
|
+
|
31
|
+
$ cuketagger add:foo path/to/some.feature
|
32
|
+
|
33
|
+
removed,
|
34
|
+
|
35
|
+
$ cuketagger remove:foo path/to/some.feature
|
36
|
+
|
37
|
+
or replaced.
|
38
|
+
|
39
|
+
$ cuketagger replace:old_tag:new_tag path/to/some.feature
|
40
|
+
|
41
|
+
Multiple tags and files can be manipulated at the same time
|
42
|
+
|
43
|
+
$ cuketagger remove:wip add:release5 replace:qa:prod features/foo.feature:6 features/bar.feature
|
44
|
+
|
45
|
+
and the modified file content will be output to the console. To modify the files
|
46
|
+
themselves, add the explicit `force` tag.
|
47
|
+
|
48
|
+
$ cuketagger --force remove:wip add:release5 replace:qa:prod features/foo.feature:6 features/bar.feature
|
49
|
+
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
1. Fork it
|
54
|
+
2. Create your feature branch (off of the development branch)
|
55
|
+
`git checkout -b my-new-feature`
|
56
|
+
3. Commit your changes
|
57
|
+
`git commit -am 'Add some feature'`
|
58
|
+
4. Push to the branch
|
59
|
+
`git push origin my-new-feature`
|
60
|
+
5. Create new Pull Request
|
data/Rakefile
CHANGED
@@ -1,55 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
s.bindir = 'bin'
|
23
|
-
s.executables = Dir['bin/*'].map { |f| File.basename(f) }
|
24
|
-
|
25
|
-
s.add_runtime_dependency 'cucumber', '>= 0.9.2'
|
26
|
-
end
|
27
|
-
|
28
|
-
Rake::GemPackageTask.new(spec) do |pkg|
|
29
|
-
pkg.gem_spec = spec
|
30
|
-
end
|
31
|
-
|
32
|
-
namespace :gem do
|
33
|
-
desc "install the gem locally"
|
34
|
-
task :install => [:package] do
|
35
|
-
sh %{sudo #{Gem.ruby} -S gem install pkg/#{GEM_NAME}-#{GEM_VERSION}}
|
36
|
-
end
|
37
|
-
|
38
|
-
desc "Create a .gemspec file"
|
39
|
-
task :spec do
|
40
|
-
file = "#{GEM_NAME.downcase}.gemspec"
|
41
|
-
File.unlink file if ::File.exists?(file)
|
42
|
-
File.open(file, "w+") { |f| f << spec.to_ruby }
|
43
|
-
end
|
44
|
-
|
45
|
-
desc "Release cuketagger-#{GEM_VERSION}"
|
46
|
-
task :release => [:clean, :gem] do
|
47
|
-
sh "gem push pkg/#{GEM_NAME}-#{GEM_VERSION}.gem"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
Cucumber::Rake::Task.new(:features) do |t|
|
52
|
-
t.cucumber_opts = "--format pretty"
|
53
|
-
end
|
54
|
-
|
55
|
-
task :default => :features
|
1
|
+
require 'racatt'
|
2
|
+
|
3
|
+
|
4
|
+
namespace 'cuketagger' do
|
5
|
+
Racatt.create_tasks
|
6
|
+
|
7
|
+
# The task that CI will use
|
8
|
+
task :ci_build => [:smart_test]
|
9
|
+
|
10
|
+
|
11
|
+
task :smart_test do |t, args|
|
12
|
+
rspec_args = '--pattern testing/rspec/spec/**/*_spec.rb'
|
13
|
+
cucumber_args = 'testing/cucumber/features -r testing/cucumber/features -f progress'
|
14
|
+
|
15
|
+
Rake::Task['cuketagger:test_everything'].invoke(rspec_args, cucumber_args)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
task :default => 'cuketagger:smart_test'
|
data/bin/cuketagger
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# encoding: utf-8
|
3
|
-
|
4
|
-
require File.expand_path("../../lib/cuketagger", __FILE__)
|
5
|
-
CukeTagger::Tagger.execute(ARGV)
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require File.expand_path("../../lib/cuketagger", __FILE__)
|
5
|
+
CukeTagger::Tagger.execute(ARGV)
|
data/cuketagger.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cuketagger/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cuketagger"
|
8
|
+
spec.version = CukeTagger::VERSION
|
9
|
+
spec.authors = ["Jari Bakken", "Eric Kessler"]
|
10
|
+
spec.email = ["morrow748@gmail.com"]
|
11
|
+
|
12
|
+
# todo - Update summary and description
|
13
|
+
spec.summary = "batch tagging of cucumber features and scenarios"
|
14
|
+
# spec.description = %q{TODO: Write a longer description or delete this line.}
|
15
|
+
spec.homepage = "https://github.com/jarib/cuketagger"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
|
23
|
+
spec.add_runtime_dependency 'cuke_modeler', '~>1.0'
|
24
|
+
spec.add_runtime_dependency 'cql', '~>1.0', '>= 1.3.0'
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "racatt", '~> 1.0'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
30
|
+
spec.add_development_dependency 'cucumber', '< 3.0.0'
|
31
|
+
end
|
data/lib/cuketagger.rb
CHANGED
@@ -1,18 +1,13 @@
|
|
1
|
-
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
2
|
-
|
3
|
-
require "set"
|
4
|
-
|
5
|
-
require
|
6
|
-
require
|
7
|
-
|
8
|
-
|
9
|
-
require "cuketagger/
|
10
|
-
require "cuketagger/
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
module CukeTagger
|
15
|
-
def self.log(*args)
|
16
|
-
File.open("/tmp/cuketagger.log", "a") { |file| file.puts args.inspect } if $DEBUG
|
17
|
-
end
|
18
|
-
end
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
require 'cuke_modeler'
|
5
|
+
require 'cql'
|
6
|
+
require 'cql/model_dsl'
|
7
|
+
|
8
|
+
require "cuketagger/version"
|
9
|
+
require "cuketagger/tagger"
|
10
|
+
require "cuketagger/array_list_extension" if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
|
11
|
+
|
12
|
+
module CukeTagger
|
13
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
|
-
require 'java'
|
2
|
-
|
3
|
-
class Java::JavaUtil::ArrayList
|
4
|
-
alias_method :delete, :remove
|
5
|
-
alias_method :push, :add
|
6
|
-
|
7
|
-
def index(obj)
|
8
|
-
idx = indexOf(obj)
|
9
|
-
return if idx == -1
|
10
|
-
idx
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
class Java::JavaUtil::ArrayList
|
4
|
+
alias_method :delete, :remove
|
5
|
+
alias_method :push, :add
|
6
|
+
|
7
|
+
def index(obj)
|
8
|
+
idx = indexOf(obj)
|
9
|
+
return if idx == -1
|
10
|
+
idx
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
data/lib/cuketagger/tagger.rb
CHANGED
@@ -1,130 +1,231 @@
|
|
1
|
-
module CukeTagger
|
2
|
-
class Tagger
|
3
|
-
USAGE = "#{File.basename $0} [-v|--version] [-f|--force] [add|remove|replace]:TAG[:REPLACEMENT] [FILE[:LINE]]+"
|
4
|
-
|
5
|
-
def self.execute(args)
|
6
|
-
new.execute(args)
|
7
|
-
end
|
8
|
-
|
9
|
-
def execute(args)
|
10
|
-
abort(USAGE) if args.empty? || args.first =~ /^(-h|--help)$/
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
1
|
+
module CukeTagger
|
2
|
+
class Tagger
|
3
|
+
USAGE = "#{File.basename $0} [-v|--version] [-f|--force] [add|remove|replace]:TAG[:REPLACEMENT] [FILE[:LINE]]+"
|
4
|
+
|
5
|
+
def self.execute(args)
|
6
|
+
new.execute(args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute(args)
|
10
|
+
abort(USAGE) if args.empty? || args.first =~ /^(-h|--help)$/
|
11
|
+
|
12
|
+
force = false
|
13
|
+
|
14
|
+
args.each do |arg|
|
15
|
+
case arg
|
16
|
+
when /^-v|--version$/
|
17
|
+
puts CukeTagger::Version
|
18
|
+
when /^(.+?\.feature)((:\d+)*)$/
|
19
|
+
add_feature $1, $2.to_s
|
20
|
+
when /^(add|remove):(.+?)$/
|
21
|
+
alterations << [$1.to_sym, $2]
|
22
|
+
when /^(replace):(.+?):(.+)$/
|
23
|
+
alterations << [$1.to_sym, [$2, $3]]
|
24
|
+
when /^(-f|--force)$/
|
25
|
+
force = true
|
26
|
+
else
|
27
|
+
abort(USAGE)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
alterations.uniq!
|
32
|
+
|
33
|
+
files = features_to_change.map { |file, line| file }.uniq
|
34
|
+
files.each { |file| parse file, force }
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
|
41
|
+
def parse(file_path, write)
|
42
|
+
return unless feature_to_change?(file_path)
|
43
|
+
|
44
|
+
content = File.open(file_path) { |file| file.readlines }
|
45
|
+
|
46
|
+
feature_model = CukeModeler::FeatureFile.new(file_path).feature
|
47
|
+
|
48
|
+
io = write ? File.open(file_path, "w") : $stdout
|
49
|
+
|
50
|
+
begin
|
51
|
+
taggable_things = collect_taggable_models(feature_model)
|
52
|
+
|
53
|
+
# Elements must be altered in the order that they appear in the file in order to
|
54
|
+
# guarantee that any line adjustments are applied appropriately.
|
55
|
+
taggable_things.sort!{|a,b| a.source_line <=> b.source_line}
|
56
|
+
|
57
|
+
taggable_things.each do |thing|
|
58
|
+
if thing_to_tag?(thing)
|
59
|
+
alterations.each do |alteration|
|
60
|
+
alter_thing(thing, alteration, content)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
content = content.join
|
66
|
+
|
67
|
+
io.write(content)
|
68
|
+
ensure
|
69
|
+
io.close unless io == $stdout
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def should_alter?(uri, element)
|
74
|
+
features_to_change.any? do |file, line|
|
75
|
+
file == uri && (element.line == line || (line.nil? && element.kind_of?(Gherkin::Formatter::Model::Feature)))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_feature(path, lines)
|
80
|
+
lines = lines.split(":")
|
81
|
+
lines.delete ""
|
82
|
+
|
83
|
+
if lines.empty?
|
84
|
+
features_to_change << [path, nil]
|
85
|
+
else
|
86
|
+
lines.each do |line|
|
87
|
+
features_to_change << [path, Integer(line)]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def alterations
|
93
|
+
@alterations ||= []
|
94
|
+
end
|
95
|
+
|
96
|
+
# todo - add warning if there are features that do not get changed (e.g. the user provided an incorrect file/line number or replaces a non-existant tag)
|
97
|
+
def features_to_change
|
98
|
+
@features_to_change ||= Set.new
|
99
|
+
end
|
100
|
+
|
101
|
+
def feature_to_change?(file_name)
|
102
|
+
features_to_change.any? { |name, line_number| name == file_name }
|
103
|
+
end
|
104
|
+
|
105
|
+
def thing_to_tag?(thing)
|
106
|
+
#todo - pass in file name as well for performance?
|
107
|
+
features_to_change.any? { |name, line_number|
|
108
|
+
name_match = (name == thing.get_ancestor(:feature_file).path)
|
109
|
+
number_match = (thing.source_line == line_number)
|
110
|
+
|
111
|
+
(name_match && number_match) || (name_match && thing.is_a?(CukeModeler::Feature) && line_number.nil?
|
112
|
+
)
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
def collect_taggable_models(feature_model)
|
117
|
+
results = feature_model.query do
|
118
|
+
select :model
|
119
|
+
from scenarios, outlines, examples
|
120
|
+
end
|
121
|
+
[feature_model] + results.collect { |result| result[:model] }
|
122
|
+
end
|
123
|
+
|
124
|
+
def alter_thing(thing, alteration, content)
|
125
|
+
|
126
|
+
case alteration.first
|
127
|
+
when :add
|
128
|
+
add_tag(thing, alteration.last, content)
|
129
|
+
when :remove
|
130
|
+
remove_tag(thing, alteration.last, content)
|
131
|
+
when :replace
|
132
|
+
replace_tag(thing, alteration.last.first, alteration.last.last, content)
|
133
|
+
else
|
134
|
+
raise "Unknown alteration type: #{alteration.first}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def replace_tag(thing, old_tag, new_tag, content)
|
139
|
+
@file_offset ||= Hash.new(0)
|
140
|
+
@line_removed ||= {}
|
141
|
+
|
142
|
+
relevant_tag = thing.tags.select { |tag_model| tag_model.name == "@#{old_tag}" }.first
|
143
|
+
|
144
|
+
if relevant_tag
|
145
|
+
insertion_index = relevant_tag.source_line + @file_offset[thing.get_ancestor(:feature_file).path] - 1
|
146
|
+
content[insertion_index] = content[insertion_index].sub("@#{old_tag}", "@#{new_tag}")
|
147
|
+
else
|
148
|
+
$stderr.puts "expected \"@#{old_tag}\" at #{thing.get_ancestor(:feature_file).name}:#{thing.source_line}, skipping"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def add_tag(thing, tag, content)
|
153
|
+
@file_offset ||= Hash.new(0)
|
154
|
+
@line_removed ||= {}
|
155
|
+
|
156
|
+
insertion_index = thing.source_line + @file_offset[thing.get_ancestor(:feature_file).path] - 2
|
157
|
+
|
158
|
+
if new_line_needed?(thing, content, insertion_index)
|
159
|
+
insertion_index += 1
|
160
|
+
content.insert(insertion_index, '')
|
161
|
+
|
162
|
+
@line_removed[thing] = false
|
163
|
+
@file_offset[thing.get_ancestor(:feature_file).path] += 1
|
164
|
+
end
|
165
|
+
|
166
|
+
empty_line = content[insertion_index].chomp =~ /^\s*$/
|
167
|
+
trim_line(content, insertion_index, !empty_line)
|
168
|
+
|
169
|
+
content[insertion_index] = content[insertion_index].chomp + "#{tag_spacing(content, insertion_index)}@#{tag}\n"
|
170
|
+
end
|
171
|
+
|
172
|
+
def remove_tag(thing, tag, content)
|
173
|
+
@file_offset ||= Hash.new(0)
|
174
|
+
@line_removed ||= {}
|
175
|
+
|
176
|
+
relevant_tag = thing.tags.select { |tag_model| tag_model.name == "@#{tag}" }.first
|
177
|
+
|
178
|
+
return unless relevant_tag
|
179
|
+
|
180
|
+
insertion_index = relevant_tag.source_line + @file_offset[thing.get_ancestor(:feature_file).path] - 1
|
181
|
+
content[insertion_index] = content[insertion_index].sub(/@#{Regexp.escape(tag)} ?/, '')
|
182
|
+
|
183
|
+
trim_line(content, insertion_index, true)
|
184
|
+
|
185
|
+
if content[insertion_index] =~ /^\s*$/
|
186
|
+
content[insertion_index] = nil
|
187
|
+
content.compact!
|
188
|
+
@file_offset[thing.get_ancestor(:feature_file).path] -= 1
|
189
|
+
@line_removed[thing] = true
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def trim_line(content, insertion_index, keep_indentation)
|
194
|
+
line_match = content[insertion_index].match(/^(\s*)(\S.*)?/)
|
195
|
+
indentation = line_match[1]
|
196
|
+
line_content = line_match[2]
|
197
|
+
|
198
|
+
trimmed_line = keep_indentation ? indentation : ''
|
199
|
+
trimmed_line += line_content.squeeze(' ').strip if line_content
|
200
|
+
trimmed_line = "#{trimmed_line.chomp}\n"
|
201
|
+
|
202
|
+
content[insertion_index] = trimmed_line
|
203
|
+
end
|
204
|
+
|
205
|
+
def tag_spacing(content, insertion_index)
|
206
|
+
if content[insertion_index] =~ /\S/
|
207
|
+
' '
|
208
|
+
else
|
209
|
+
next_line_leading_spaces = content[insertion_index + 1].match(/^(\s*)/)[1]
|
210
|
+
' ' * next_line_leading_spaces.length
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def new_line_needed?(thing, content, insertion_index)
|
215
|
+
line_was_removed?(thing) || (non_tag_line?(content, insertion_index) && non_empty_line?(content, insertion_index))
|
216
|
+
end
|
217
|
+
|
218
|
+
def line_was_removed?(thing)
|
219
|
+
@line_removed[thing]
|
220
|
+
end
|
221
|
+
|
222
|
+
def non_tag_line?(content, insertion_index)
|
223
|
+
content[insertion_index] !~ /^\s*@/
|
224
|
+
end
|
225
|
+
|
226
|
+
def non_empty_line?(content, insertion_index)
|
227
|
+
content[insertion_index] !~ /^\s*$/
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
end
|