matchdoc 0.0.1
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 +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +49 -0
- data/Rakefile +2 -0
- data/lib/matchdoc.rb +4 -0
- data/lib/matchdoc/matcher.rb +54 -0
- data/lib/matchdoc/rspec.rb +15 -0
- data/lib/matchdoc/version.rb +3 -0
- data/matchdoc.gemspec +27 -0
- data/spec/matchdoc_spec.rb +78 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e83bb9ff1361427d28ea5863da452f19b0d2ecf5
|
4
|
+
data.tar.gz: 8148563e753ebcbf706aed7211e8fcfdd45a4c88
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5b0fcba5e9a7272229b55d51374412b217009c315197b2000de603e444bd92ee6a07402092b268378e22ff9d812e2eec5c6304daa2151c4e19f85fb0736db8b7
|
7
|
+
data.tar.gz: 8a1d4c6e945e43e11dafe92d462aab4da5af5b703b5de743fd2e4e43db66e78d3433d4d5d4f69b53d0639e2bdde264c2e304baf95b6d15dcbaa8038077270891
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Stephen Prater
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Matchdoc
|
2
|
+
|
3
|
+
Provides a template against which a string can be matched, particularly in RSpec
|
4
|
+
|
5
|
+
For longer strings it's not always possible or desirable to know the exact
|
6
|
+
output of the string - you might know that every line in a file shoudld
|
7
|
+
contain a price, but not what that price will be. This provides an RSpec
|
8
|
+
matcher for that exact problem.
|
9
|
+
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'matchdoc'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install matchdoc
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
To specify a template construct a string (probably with a heredoc) with
|
30
|
+
embedded Regex where you want dynamic content. If you are wanting to match a
|
31
|
+
list of 3 product SKUs and prices, you might do this.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
<<-LIST
|
35
|
+
product_sku, price
|
36
|
+
#{/[A-Z]{13}/}, #{/\$(\d)[1,2]\.\d\d}
|
37
|
+
#{/[A-Z]{13}/}, #{/\$(\d)[1,2]\.\d\d}
|
38
|
+
#{/[A-Z]{13}/}, #{/\$(\d)[1,2]\.\d\d}
|
39
|
+
LIST
|
40
|
+
```ruby
|
41
|
+
|
42
|
+
|
43
|
+
## Contributing
|
44
|
+
|
45
|
+
1. Fork it ( https://github.com/[my-github-username]/matchdoc/fork )
|
46
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
47
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
48
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
49
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/matchdoc.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Matchdoc
|
5
|
+
class Matcher
|
6
|
+
class FailedChunk < StandardError
|
7
|
+
def initialize(scanner, chunk)
|
8
|
+
failed_chunk = YAML.load(%Q(---\n"#{chunk.source}"\n))
|
9
|
+
super("Expected `#{scanner.rest[0..failed_chunk.size-1]}` to match `#{failed_chunk}`")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :failed_chunk
|
14
|
+
|
15
|
+
def initialize(subject)
|
16
|
+
scanner = StringScanner.new(subject)
|
17
|
+
@match_chunks = []
|
18
|
+
until scanner.eos?
|
19
|
+
break unless scanner.scan_until(/\(\?[-mix]{4}:/) #regex prefix
|
20
|
+
@match_chunks << Regexp.new(Regexp.escape(scanner.pre_match))
|
21
|
+
regex_sub = /\((?>[^()]|(\g<0>))*\)/.match(scanner.matched+scanner.post_match).to_s
|
22
|
+
@match_chunks << Regexp.new(regex_sub)
|
23
|
+
scanner.pos = scanner.pos + (regex_sub.length - 7)
|
24
|
+
scanner.string = scanner.rest
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def match!(subject)
|
29
|
+
scanner = StringScanner.new(subject)
|
30
|
+
scanned_chunks = []
|
31
|
+
@match_chunks.each.with_index do |chunk, i|
|
32
|
+
unless scanned_chunks[i] = scanner.scan(chunk)
|
33
|
+
raise FailedChunk.new(scanner, chunk)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
scanned_chunks
|
38
|
+
end
|
39
|
+
|
40
|
+
def =~(subject)
|
41
|
+
begin
|
42
|
+
match!(subject)
|
43
|
+
rescue FailedChunk
|
44
|
+
false
|
45
|
+
else
|
46
|
+
true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
@match_chunks.map { |i| '/' + YAML.load(%Q(---\n"#{i.source}"\n)) + '/' }.join
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'matchdoc/matcher'
|
2
|
+
|
3
|
+
RSpec::Matchers.define :match_template do |expected|
|
4
|
+
match_unless_raises Matchdoc::Matcher::FailedChunk do |actual|
|
5
|
+
Matchdoc::Matcher.new(expected).match!(actual)
|
6
|
+
end
|
7
|
+
|
8
|
+
def diffable?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
failure_message do
|
13
|
+
@rescued_exception.message
|
14
|
+
end
|
15
|
+
end
|
data/matchdoc.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'matchdoc/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "matchdoc"
|
8
|
+
spec.version = Matchdoc::VERSION
|
9
|
+
spec.authors = ["Stephen Prater"]
|
10
|
+
spec.email = ["me@stephenprater.com"]
|
11
|
+
spec.summary = %q{Match long strings against templates with dynamic areas.}
|
12
|
+
spec.description = %q{For longer strings it's not always possible or desirable to know
|
13
|
+
the exact output of the string - you might know that every line in
|
14
|
+
a file shoudld contain a price, but not what that price will be.
|
15
|
+
This provides an RSpec matcher for that exact problem.}
|
16
|
+
spec.homepage = ""
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0")
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
27
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'matchdoc/rspec'
|
3
|
+
|
4
|
+
describe Matchdoc::Matcher do
|
5
|
+
|
6
|
+
let(:matchdocument) { <<-TEMPLATE
|
7
|
+
title, name, #{/[a-z]+/}
|
8
|
+
Title, #{/(.{0,10}?,)/} #{/[0-9]/}
|
9
|
+
TEMPLATE
|
10
|
+
}
|
11
|
+
|
12
|
+
let(:successful_doc) { <<-TEMPLATE
|
13
|
+
title, name, something
|
14
|
+
Title, something, 2
|
15
|
+
TEMPLATE
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:failing_doc_on_first_chunk) { <<-TEMPLATE
|
19
|
+
title, name, Something
|
20
|
+
Title, something, 2
|
21
|
+
TEMPLATE
|
22
|
+
}
|
23
|
+
|
24
|
+
let(:failing_doc_on_second_chunk) { <<-TEMPLATE
|
25
|
+
title, name, something
|
26
|
+
Title, somethingentirelytolong, 2
|
27
|
+
TEMPLATE
|
28
|
+
}
|
29
|
+
|
30
|
+
let(:failing_doc_on_third_chunk) { <<-TEMPLATE
|
31
|
+
title, name, something
|
32
|
+
Title, something, Q
|
33
|
+
TEMPLATE
|
34
|
+
}
|
35
|
+
|
36
|
+
subject { Matchdoc::Matcher.new(matchdocument) }
|
37
|
+
|
38
|
+
it 'matches a document template' do
|
39
|
+
expect(subject.match!(successful_doc)).to be_truthy
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when it fails on the first chunk' do
|
43
|
+
it 'fails to match a document template' do
|
44
|
+
expect { subject.match!(failing_doc_on_first_chunk) }
|
45
|
+
.to raise_error(Matchdoc::Matcher::FailedChunk, "Expected `Something\n ` to match `(?-mix:[a-z]+)`")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when it fails on the second chunk' do
|
50
|
+
it 'fails to match a document template' do
|
51
|
+
expect { subject.match!(failing_doc_on_second_chunk) }
|
52
|
+
.to raise_error(Matchdoc::Matcher::FailedChunk, "Expected `somethingentirelyto` to match `(?-mix:(.{0,10}?,))`")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when it fails on the third chunk' do
|
57
|
+
it 'fails to match a document template' do
|
58
|
+
expect { subject.match!(failing_doc_on_third_chunk) }
|
59
|
+
.to raise_error(Matchdoc::Matcher::FailedChunk, "Expected `Q\n` to match `(?-mix:[0-9])`")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'it can use the matchy operator' do
|
64
|
+
it 'returns true' do
|
65
|
+
expect(subject =~ successful_doc).to be true
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'returns false' do
|
69
|
+
expect(subject =~ failing_doc_on_first_chunk).to be false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'to_s' do
|
74
|
+
it 'returns a string rep of the match template' do
|
75
|
+
expect(subject.to_s).to eq "/ title, name, //(?-mix:[a-z]+)//\n Title, //(?-mix:(.{0,10}?,))// //(?-mix:[0-9])/"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: matchdoc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephen Prater
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.2'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.2'
|
55
|
+
description: "For longer strings it's not always possible or desirable to know \n
|
56
|
+
\ the exact output of the string - you might know that every
|
57
|
+
line in\n a file shoudld contain a price, but not what
|
58
|
+
that price will be.\n This provides an RSpec matcher for
|
59
|
+
that exact problem."
|
60
|
+
email:
|
61
|
+
- me@stephenprater.com
|
62
|
+
executables: []
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- .gitignore
|
67
|
+
- Gemfile
|
68
|
+
- LICENSE.txt
|
69
|
+
- README.md
|
70
|
+
- Rakefile
|
71
|
+
- lib/matchdoc.rb
|
72
|
+
- lib/matchdoc/matcher.rb
|
73
|
+
- lib/matchdoc/rspec.rb
|
74
|
+
- lib/matchdoc/version.rb
|
75
|
+
- matchdoc.gemspec
|
76
|
+
- spec/matchdoc_spec.rb
|
77
|
+
homepage: ''
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 2.0.14
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: Match long strings against templates with dynamic areas.
|
101
|
+
test_files:
|
102
|
+
- spec/matchdoc_spec.rb
|
103
|
+
has_rdoc:
|