librariesio-gem-parser 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +19 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +55 -0
- data/Rakefile +9 -0
- data/lib/gemnasium/parser.rb +35 -0
- data/lib/gemnasium/parser/configuration.rb +11 -0
- data/lib/gemnasium/parser/gemfile.rb +109 -0
- data/lib/gemnasium/parser/gemspec.rb +38 -0
- data/lib/gemnasium/parser/patterns.rb +69 -0
- data/lib/gemnasium/parser/podfile.rb +91 -0
- data/lib/gemnasium/parser/podspec.rb +38 -0
- data/librariesio-gem-parser.gemspec +20 -0
- data/spec/gemnasium/parser/gemfile_spec.rb +294 -0
- data/spec/gemnasium/parser/gemspec_spec.rb +159 -0
- data/spec/gemnasium/parser/podfile_spec.rb +239 -0
- data/spec/gemnasium/parser/podspec_spec.rb +150 -0
- data/spec/gemnasium/parser_spec.rb +34 -0
- data/spec/spec_helper.rb +1 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ee10e89cac8d75e23956264a511b98302f723179
|
4
|
+
data.tar.gz: 6cf5b395df0bab001f382b2bf3d2604eb0e768c7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 934211a80747662da08b4d997facdcf7086351297ae527b0466a62977708db039238d9bc1d63c5bf87eb0d74d80311a055e40e9c4dec92409192f1414cfbc5ac
|
7
|
+
data.tar.gz: ee17f4dc806bc5e49b2c791f4a5c145c6703fee288b7be5c53a93c00c90565e3f7a7c67a113f77ff31f52d7df818c147a4bd348f0186ebc0b02efd6e03334365
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
## 0.1.9 / 2012-11-19
|
2
|
+
|
3
|
+
Bugfixes:
|
4
|
+
|
5
|
+
* remove CR chars from content before parsing since it breaks patterns matching
|
6
|
+
|
7
|
+
## 0.1.8 / 2012-11-18
|
8
|
+
|
9
|
+
Bugfixes:
|
10
|
+
|
11
|
+
* support :github option and exclude gems that use it
|
12
|
+
* add CHANGELOG
|
13
|
+
|
14
|
+
## 0.1.7 2012-10-17
|
15
|
+
|
16
|
+
Bugfixes:
|
17
|
+
|
18
|
+
* fix pattern to allow gem's
|
19
|
+
with a period
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2011 Steve Richert
|
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,55 @@
|
|
1
|
+
# Gemnasium::Parser
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/gemnasium-parser.png)](http://badge.fury.io/rb/gemnasium-parser)
|
4
|
+
[![Build Status](https://travis-ci.org/gemnasium/gemnasium-parser.png?branch=master)](https://travis-ci.org/gemnasium/gemnasium-parser)
|
5
|
+
[![Dependency Status](https://gemnasium.com/laserlemon/gemnasium-parser.png)](https://gemnasium.com/laserlemon/gemnasium-parser)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/laserlemon/gemnasium-parser.png)](https://codeclimate.com/github/laserlemon/gemnasium-parser)
|
7
|
+
[![Coverage Status](https://coveralls.io/repos/laserlemon/gemnasium-parser/badge.png?branch=master)](https://coveralls.io/r/laserlemon/gemnasium-parser)
|
8
|
+
|
9
|
+
The [Gemnasium](https://gemnasium.com/) parser determines gem dependencies from gemfiles and gemspecs, without evaluating the Ruby.
|
10
|
+
|
11
|
+
## Why?
|
12
|
+
|
13
|
+
[Bundler](http://gembundler.com/) is wonderful. It takes your gemfile and your gemspec (both just Ruby) and evaluates them, determining your gem dependencies. This works great locally and even on your production server… but only because you can be trusted!
|
14
|
+
|
15
|
+
An untrustworthy character could put some pretty nasty stuff in a gemfile. If Gemnasium were to blindly evaluate that Ruby on its servers, havoc would ensue.
|
16
|
+
|
17
|
+
### Solution #1
|
18
|
+
|
19
|
+
If evaluating Ruby is so dangerous, just sandbox it! [Travis CI](http://travis-ci.org/) runs its builds inside isolated environments built with [Vagrant](http://vagrantup.com/). That way, if anything goes awry, it’s in a controlled environment.
|
20
|
+
|
21
|
+
This is entirely possible with Gemnasium, but it’s impractical. Gemfiles often `require` other files in the repository. So to evaluate a gemfile, Gemnasium needs to clone the entire repo. That’s an expensive operation when only a couple files determine the dependencies.
|
22
|
+
|
23
|
+
### Solution #2
|
24
|
+
|
25
|
+
Parse Ruby like Ruby parses Ruby.
|
26
|
+
|
27
|
+
Ruby 1.9 includes a library called Ripper. Ripper is a Ruby parsing library that can break down a gemfile or gemspec into bite-sized chunks, without evaluating the source. Then it can be searched for just the methods that matter.
|
28
|
+
|
29
|
+
The problem is that it’s hard to make heads or tails from Ripper’s output, at least for me. I could see the Gemnasium parser one day moving to this strategy. But not today.
|
30
|
+
|
31
|
+
### Third try’s the charm
|
32
|
+
|
33
|
+
If we can’t evaluate the Ruby and Ripper’s output is unmanageable, how else can we find patterns in a gemfile or gemspec and get usable output?
|
34
|
+
|
35
|
+
Regular expressions!
|
36
|
+
|
37
|
+
The Gemnasium parser, for both gemfiles and gemspecs, is based on a number of Ruby regular expressions. These patterns match `gem` method calls in gemfiles and `add_dependency` calls in gemspecs.
|
38
|
+
|
39
|
+
For a more comprehensive list of its abilities, see the [specs](https://github.com/laserlemon/gemnasium-parser/tree/master/spec).
|
40
|
+
|
41
|
+
## Contributing <a name="contributing"></a>
|
42
|
+
|
43
|
+
1. Fork it
|
44
|
+
2. Create your branch (`git checkout -b my-bugfix`)
|
45
|
+
3. Commit your changes (`git commit -am "Fix my bug"`)
|
46
|
+
4. Push your branch (`git push origin my-bugfix`)
|
47
|
+
5. Send a pull request
|
48
|
+
|
49
|
+
## Problems?
|
50
|
+
|
51
|
+
If you have a gemfile or gemspec that the Gemnasium parser screws up…
|
52
|
+
|
53
|
+
1. Boil it down to its simplest problematic form
|
54
|
+
2. Write a failing spec
|
55
|
+
3. See [Contributing](#contributing)
|
data/Rakefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "gemnasium/parser/configuration"
|
2
|
+
require "gemnasium/parser/gemfile"
|
3
|
+
require "gemnasium/parser/podfile"
|
4
|
+
require "gemnasium/parser/gemspec"
|
5
|
+
require "gemnasium/parser/podspec"
|
6
|
+
|
7
|
+
module Gemnasium
|
8
|
+
module Parser
|
9
|
+
extend Configuration
|
10
|
+
|
11
|
+
def self.gemfile(content)
|
12
|
+
# Remove CR chars "\r" from content since it breaks Patterns matching
|
13
|
+
# TODO: Find something cleaner than this workaround
|
14
|
+
Gemnasium::Parser::Gemfile.new(content.gsub("\r",''))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.podfile(content)
|
18
|
+
# Remove CR chars "\r" from content since it breaks Patterns matching
|
19
|
+
# TODO: Find something cleaner than this workaround
|
20
|
+
Gemnasium::Parser::Podfile.new(content.gsub("\r",''))
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.gemspec(content)
|
24
|
+
# Remove CR chars "\r" from content since it breaks Patterns matching
|
25
|
+
# TODO: Find something cleaner than this workaround
|
26
|
+
Gemnasium::Parser::Gemspec.new(content.gsub("\r",''))
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.podspec(content)
|
30
|
+
# Remove CR chars "\r" from content since it breaks Patterns matching
|
31
|
+
# TODO: Find something cleaner than this workaround
|
32
|
+
Gemnasium::Parser::Podspec.new(content.gsub("\r",''))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require "bundler"
|
2
|
+
require "gemnasium/parser/patterns"
|
3
|
+
|
4
|
+
module Gemnasium
|
5
|
+
module Parser
|
6
|
+
class Gemfile
|
7
|
+
attr_reader :content
|
8
|
+
|
9
|
+
def initialize(content)
|
10
|
+
@content = content
|
11
|
+
end
|
12
|
+
|
13
|
+
def dependencies
|
14
|
+
@dependencies ||= [].tap do |deps|
|
15
|
+
gem_matches.each do |match|
|
16
|
+
dep = dependency(match)
|
17
|
+
deps << dep if dep
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def gemspec
|
23
|
+
@gemspec = if gemspec_match
|
24
|
+
opts = Patterns.options(gemspec_match["opts"])
|
25
|
+
path = opts["path"]
|
26
|
+
name = opts["name"] || "*"
|
27
|
+
File.join(*[path, "#{name}.gemspec"].compact)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def gemspec?
|
32
|
+
!!gemspec
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def gem_matches
|
37
|
+
@gem_matches ||= matches(Patterns::GEM_CALL)
|
38
|
+
end
|
39
|
+
|
40
|
+
def matches(pattern)
|
41
|
+
[].tap{|m| content.scan(pattern){ m << Regexp.last_match } }
|
42
|
+
end
|
43
|
+
|
44
|
+
def dependency(match)
|
45
|
+
opts = Patterns.options(match["opts"])
|
46
|
+
clean!(match, opts)
|
47
|
+
name, reqs = match["name"], [match["req1"], match["req2"]].compact
|
48
|
+
Bundler::Dependency.new(name, reqs, opts).tap do |dep|
|
49
|
+
line = content.slice(0, match.begin(0)).count("\n") + 1
|
50
|
+
dep.instance_variable_set(:@line, line)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def groups(match)
|
55
|
+
group = group_matches.detect{|m| in_block?(match, m) }
|
56
|
+
group && Patterns.values(group[:grps])
|
57
|
+
end
|
58
|
+
|
59
|
+
def in_block?(inner, outer)
|
60
|
+
outer.begin(:blk) <= inner.begin(0) && outer.end(:blk) >= inner.end(0)
|
61
|
+
end
|
62
|
+
|
63
|
+
def group_matches
|
64
|
+
@group_matches ||= matches(Patterns::GROUP_CALL)
|
65
|
+
end
|
66
|
+
|
67
|
+
def git?(match, opts)
|
68
|
+
opts["git"] || in_git_block?(match)
|
69
|
+
end
|
70
|
+
|
71
|
+
def github?(match, opts)
|
72
|
+
opts["github"]
|
73
|
+
end
|
74
|
+
|
75
|
+
def in_git_block?(match)
|
76
|
+
git_matches.any?{|m| in_block?(match, m) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def git_matches
|
80
|
+
@git_matches ||= matches(Patterns::GIT_CALL)
|
81
|
+
end
|
82
|
+
|
83
|
+
def path?(match, opts)
|
84
|
+
opts["path"] || in_path_block?(match)
|
85
|
+
end
|
86
|
+
|
87
|
+
def in_path_block?(match)
|
88
|
+
path_matches.any?{|m| in_block?(match, m) }
|
89
|
+
end
|
90
|
+
|
91
|
+
def path_matches
|
92
|
+
@path_matches ||= matches(Patterns::PATH_CALL)
|
93
|
+
end
|
94
|
+
|
95
|
+
def clean!(match, opts)
|
96
|
+
opts["group"] ||= opts.delete("groups")
|
97
|
+
opts["group"] ||= groups(match)
|
98
|
+
groups = Array(opts["group"]).flatten.compact
|
99
|
+
runtime = groups.empty? || !(groups & Parser.runtime_groups).empty?
|
100
|
+
opts["type"] ||= runtime ? :runtime : :development
|
101
|
+
end
|
102
|
+
|
103
|
+
def gemspec_match
|
104
|
+
return @gemspec_match if defined?(@gemspec_match)
|
105
|
+
@gemspec_match = content.match(Patterns::GEMSPEC_CALL)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gemnasium
|
2
|
+
module Parser
|
3
|
+
class Gemspec
|
4
|
+
attr_reader :content
|
5
|
+
|
6
|
+
def initialize(content)
|
7
|
+
@content = content
|
8
|
+
end
|
9
|
+
|
10
|
+
def dependencies
|
11
|
+
@dependencies ||= [].tap do |deps|
|
12
|
+
runtime_matches.each do |match|
|
13
|
+
dep = dependency(match)
|
14
|
+
deps << dep
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def runtime_matches
|
21
|
+
@runtime_matches ||= matches(Patterns::ADD_DEPENDENCY_CALL)
|
22
|
+
end
|
23
|
+
|
24
|
+
def matches(pattern)
|
25
|
+
[].tap{|m| content.scan(pattern){ m << Regexp.last_match } }
|
26
|
+
end
|
27
|
+
|
28
|
+
def dependency(match)
|
29
|
+
name, reqs = match["name"], [match["req1"], match["req2"]].compact
|
30
|
+
type = match["type"] =~ /development/ ? :development : :runtime
|
31
|
+
Bundler::Dependency.new(name, reqs, "type" => type).tap do |dep|
|
32
|
+
line = content.slice(0, match.begin(0)).count("\n") + 1
|
33
|
+
dep.instance_variable_set(:@line, line)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Gemnasium
|
2
|
+
module Parser
|
3
|
+
module Patterns
|
4
|
+
GEM_NAME = /[a-zA-Z0-9\-_\.]+/
|
5
|
+
QUOTED_GEM_NAME = /(?:(?<gq>["'])(?<name>#{GEM_NAME})\k<gq>|%q<(?<name>#{GEM_NAME})>)/
|
6
|
+
|
7
|
+
QUOTED_POD_NAME = /(?:(?<gq>["'])(?<name>#{GEM_NAME})(\/[a-zA-Z0-9\-_\.]+)?\k<gq>|%q<(?<name>#{GEM_NAME})(\/[a-zA-Z0-9\-_\.]+)?>)/
|
8
|
+
|
9
|
+
MATCHER = /(?:=|!=|>|<|>=|<=|~>)/
|
10
|
+
VERSION = /[0-9]+(?:\.[a-zA-Z0-9]+)*/
|
11
|
+
REQUIREMENT = /[ \t]*(?:#{MATCHER}[ \t]*)?#{VERSION}[ \t]*/
|
12
|
+
REQUIREMENT_LIST = /(?<qr1>["'])(?<req1>#{REQUIREMENT})\k<qr1>(?:[ \t]*,[ \t]*(?<qr2>["'])(?<req2>#{REQUIREMENT})\k<qr2>)?/
|
13
|
+
REQUIREMENTS = /(?:#{REQUIREMENT_LIST}|\[[ \t]*#{REQUIREMENT_LIST}[ \t]*\])/
|
14
|
+
|
15
|
+
KEY = /(?::\w+|:?"\w+"|:?'\w+')/
|
16
|
+
SYMBOL = /(?::\w+|:"[^"#]+"|:'[^']+')/
|
17
|
+
STRING = /(?:"[^"#]*"|'[^']*')/
|
18
|
+
BOOLEAN = /(?:true|false)/
|
19
|
+
NIL = /nil/
|
20
|
+
ELEMENT = /(?:#{SYMBOL}|#{STRING})/
|
21
|
+
ARRAY = /\[(?:#{ELEMENT}(?:[ \t]*,[ \t]*#{ELEMENT})*)?\]/
|
22
|
+
VALUE = /(?:#{BOOLEAN}|#{NIL}|#{ELEMENT}|#{ARRAY}|)/
|
23
|
+
PAIR = /(?:(#{KEY})[ \t]*=>[ \t]*(#{VALUE})|(\w+):[ \t]+(#{VALUE}))/
|
24
|
+
OPTIONS = /#{PAIR}(?:[ \t]*,[ \t]*#{PAIR})*/
|
25
|
+
COMMENT = /(#[^\n]*)?/
|
26
|
+
|
27
|
+
GEM_CALL = /^[ \t]*gem\(?[ \t]*#{QUOTED_GEM_NAME}(?:[ \t]*,[ \t]*#{REQUIREMENT_LIST})?(?:[ \t]*,[ \t]*(?<opts>#{OPTIONS}))?[ \t]*\)?[ \t]*#{COMMENT}$/
|
28
|
+
POD_CALL = /^[ \t]*pod\(?[ \t]*#{QUOTED_GEM_NAME}(?:[ \t]*,[ \t]*#{REQUIREMENT_LIST})?(?:[ \t]*,[ \t]*(?<opts>#{OPTIONS}))?[ \t]*\)?[ \t]*#{COMMENT}$/
|
29
|
+
|
30
|
+
SYMBOLS = /#{SYMBOL}([ \t]*,[ \t]*#{SYMBOL})*/
|
31
|
+
GROUP_CALL = /^(?<i1>[ \t]*)group\(?[ \t]*(?<grps>#{SYMBOLS})[ \t]*\)?[ \t]+do[ \t]*?\n(?<blk>.*?)\n^\k<i1>end[ \t]*$/m
|
32
|
+
|
33
|
+
GIT_CALL = /^(?<i1>[ \t]*)git[ \(][^\n]*?do[ \t]*?\n(?<blk>.*?)\n^\k<i1>end[ \t]*$/m
|
34
|
+
|
35
|
+
PATH_CALL = /^(?<i1>[ \t]*)path[ \(][^\n]*?do[ \t]*?\n(?<blk>.*?)\n^\k<i1>end[ \t]*$/m
|
36
|
+
|
37
|
+
GEMSPEC_CALL = /^[ \t]*gemspec(?:\(?[ \t]*(?<opts>#{OPTIONS}))?[ \t]*\)?[ \t]*$/
|
38
|
+
|
39
|
+
ADD_DEPENDENCY_CALL = /^[ \t]*\w+\.add(?<type>_runtime|_development)?_dependency\(?[ \t]*#{QUOTED_GEM_NAME}(?:[ \t]*,[ \t]*#{REQUIREMENTS})?[ \t]*\)?[ \t]*#{COMMENT}$/
|
40
|
+
ADD_POD_DEPENDENCY_CALL = /^[ \t]*\w+\.dependency\(?[ \t]*#{QUOTED_POD_NAME}(?:[ \t]*,[ \t]*#{REQUIREMENTS})?[ \t]*\)?[ \t]*#{COMMENT}$/
|
41
|
+
|
42
|
+
def self.options(string)
|
43
|
+
{}.tap do |hash|
|
44
|
+
return hash unless string
|
45
|
+
pairs = Hash[*string.match(OPTIONS).captures.compact]
|
46
|
+
pairs.each{|k,v| hash[key(k)] = value(v) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.key(string)
|
51
|
+
string.tr(%(:"'), "")
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.value(string)
|
55
|
+
case string
|
56
|
+
when ARRAY then values(string.tr("[]", ""))
|
57
|
+
when SYMBOL then string.tr(%(:"'), "").to_sym
|
58
|
+
when STRING then string.tr(%("'), "")
|
59
|
+
when BOOLEAN then string == "true"
|
60
|
+
when NIL then nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.values(string)
|
65
|
+
string.strip.split(/[ \t]*,[ \t]*/).map{|v| value(v) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require "bundler"
|
2
|
+
require "gemnasium/parser/patterns"
|
3
|
+
|
4
|
+
module Gemnasium
|
5
|
+
module Parser
|
6
|
+
class Podfile
|
7
|
+
attr_reader :content
|
8
|
+
|
9
|
+
def initialize(content)
|
10
|
+
@content = content
|
11
|
+
end
|
12
|
+
|
13
|
+
def dependencies
|
14
|
+
@dependencies ||= [].tap do |deps|
|
15
|
+
pod_matches.each do |match|
|
16
|
+
dep = dependency(match)
|
17
|
+
deps << dep if dep
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def pod_matches
|
24
|
+
@pod_matches ||= matches(Patterns::POD_CALL)
|
25
|
+
end
|
26
|
+
|
27
|
+
def matches(pattern)
|
28
|
+
[].tap{|m| content.scan(pattern){ m << Regexp.last_match } }
|
29
|
+
end
|
30
|
+
|
31
|
+
def dependency(match)
|
32
|
+
opts = Patterns.options(match["opts"])
|
33
|
+
clean!(match, opts)
|
34
|
+
name, reqs = match["name"], [match["req1"], match["req2"]].compact
|
35
|
+
Bundler::Dependency.new(name, reqs, opts).tap do |dep|
|
36
|
+
line = content.slice(0, match.begin(0)).count("\n") + 1
|
37
|
+
dep.instance_variable_set(:@line, line)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def groups(match)
|
42
|
+
group = group_matches.detect{|m| in_block?(match, m) }
|
43
|
+
group && Patterns.values(group[:grps])
|
44
|
+
end
|
45
|
+
|
46
|
+
def in_block?(inner, outer)
|
47
|
+
outer.begin(:blk) <= inner.begin(0) && outer.end(:blk) >= inner.end(0)
|
48
|
+
end
|
49
|
+
|
50
|
+
def group_matches
|
51
|
+
@group_matches ||= matches(Patterns::GROUP_CALL)
|
52
|
+
end
|
53
|
+
|
54
|
+
def git?(match, opts)
|
55
|
+
opts["git"] || in_git_block?(match)
|
56
|
+
end
|
57
|
+
|
58
|
+
def github?(match, opts)
|
59
|
+
opts["github"]
|
60
|
+
end
|
61
|
+
|
62
|
+
def in_git_block?(match)
|
63
|
+
git_matches.any?{|m| in_block?(match, m) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def git_matches
|
67
|
+
@git_matches ||= matches(Patterns::GIT_CALL)
|
68
|
+
end
|
69
|
+
|
70
|
+
def path?(match, opts)
|
71
|
+
opts["path"] || in_path_block?(match)
|
72
|
+
end
|
73
|
+
|
74
|
+
def in_path_block?(match)
|
75
|
+
path_matches.any?{|m| in_block?(match, m) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def path_matches
|
79
|
+
@path_matches ||= matches(Patterns::PATH_CALL)
|
80
|
+
end
|
81
|
+
|
82
|
+
def clean!(match, opts)
|
83
|
+
opts["group"] ||= opts.delete("groups")
|
84
|
+
opts["group"] ||= groups(match)
|
85
|
+
groups = Array(opts["group"]).flatten.compact
|
86
|
+
runtime = groups.empty? || !(groups & Parser.runtime_groups).empty?
|
87
|
+
opts["type"] ||= runtime ? :runtime : :development
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|