cuketagger 1.5 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/cuketagger.svg)](https://rubygems.org/gems/cuketagger)
|
2
|
+
[![Build Status](https://travis-ci.org/enkessler/cuketagger.svg?branch=dev)](https://travis-ci.org/enkessler/cuketagger)
|
3
|
+
[![Dependency Status](https://gemnasium.com/enkessler/cuketagger.svg)](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
|