subtrigger 0.2.7 → 0.3.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.
- data/.gitignore +2 -0
- data/README.md +158 -0
- data/Rakefile +3 -9
- data/VERSION +1 -1
- data/lib/subtrigger.rb +83 -118
- data/lib/subtrigger/dsl.rb +42 -0
- data/lib/subtrigger/path.rb +82 -0
- data/lib/subtrigger/revision.rb +95 -0
- data/lib/subtrigger/rule.rb +165 -0
- data/lib/subtrigger/template.rb +96 -0
- data/subtrigger.gemspec +24 -24
- data/test/test_helper.rb +3 -0
- data/test/test_path.rb +50 -0
- data/test/test_revision.rb +43 -0
- data/test/test_rule.rb +66 -0
- data/test/test_template.rb +42 -0
- metadata +48 -26
- data/LICENSE +0 -20
- data/README.rdoc +0 -56
- data/bin/subtrigger +0 -9
- data/lib/subtrigger/email.rb +0 -56
- data/lib/subtrigger/repository.rb +0 -140
- data/lib/subtrigger/trigger.rb +0 -60
- data/test/helper.rb +0 -11
- data/test/test_email.rb +0 -44
- data/test/test_repository.rb +0 -75
- data/test/test_subtrigger.rb +0 -44
- data/test/test_trigger.rb +0 -37
@@ -0,0 +1,82 @@
|
|
1
|
+
module Subtrigger
|
2
|
+
# Our own little implementation of the path, allowing us to look up
|
3
|
+
# the location of executable files. This is because Subversion hooks
|
4
|
+
# run in a clean environment, without any environment variables such as
|
5
|
+
# <tt>$PATH</tt>. We therefore need to run (for example)
|
6
|
+
# <tt>/usr/bin/svn update</tt> rather than <tt>svn update</tt>.
|
7
|
+
#
|
8
|
+
# There is a list of default locations that will be searched, but you
|
9
|
+
# may add your own if you want to. This is useful if you've got a custom
|
10
|
+
# installation on your machine you want to use.
|
11
|
+
#
|
12
|
+
# Note: testing whether an executable exists in a given path is done using
|
13
|
+
# the unix program <tt>test</tt>, which will most likely not work on
|
14
|
+
# windows machines (untested).
|
15
|
+
#
|
16
|
+
# @example Getting the path to an executable
|
17
|
+
# Path.new.to('svn') #=> '/usr/bin'
|
18
|
+
#
|
19
|
+
# @example Adding a preferred location
|
20
|
+
# path = Path.new
|
21
|
+
# path << '/opt/local'
|
22
|
+
# path.to('svn') => '/opt/local'
|
23
|
+
#
|
24
|
+
# @author Arjan van der Gaag
|
25
|
+
# @since 0.3.0
|
26
|
+
class Path
|
27
|
+
|
28
|
+
# The default list of paths to look in, covering most of the use cases.
|
29
|
+
DEFAULT_PATHS = %w{/opt/subversion/bin /usr/sbin /usr/bin}
|
30
|
+
|
31
|
+
# Custom exception raised when a program is not found in any of the
|
32
|
+
# locations known.
|
33
|
+
NotFound = Class.new(Exception)
|
34
|
+
|
35
|
+
# A list of absolute paths on te filesystems to where the svn executables
|
36
|
+
# might be located. These are scanned in order to find the executables
|
37
|
+
# to use.
|
38
|
+
attr_reader :locations
|
39
|
+
|
40
|
+
# Start a new list of paths, starting with the <tt>DEFAULT_PATHS</tt>
|
41
|
+
def initialize
|
42
|
+
@locations = DEFAULT_PATHS.dup # use a copy to prevent global state
|
43
|
+
@exists = Hash.new do |hash, p|
|
44
|
+
hash[p] = system('test -x ' + p)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add a new path to the stack before the existing ones.
|
49
|
+
#
|
50
|
+
# @param [String] new_path is a new possible location of executables
|
51
|
+
# @return [Array<String>] the total list of paths
|
52
|
+
def <<(new_path)
|
53
|
+
@locations.unshift(new_path)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Scan all the known paths to find the given program.
|
57
|
+
#
|
58
|
+
# Note: this probably only works on unix-like systems.
|
59
|
+
#
|
60
|
+
# @todo implement memoization per argument
|
61
|
+
# @param [String] program is the name of the executable to find, like
|
62
|
+
# <tt>svn</tt>
|
63
|
+
# @return [String] the correct path to this program or nil
|
64
|
+
# @raise NotFoundException when the program is not found in any of the
|
65
|
+
# known locations
|
66
|
+
def to(program)
|
67
|
+
location = locations.find { |path| exists? File.join(path, program) }
|
68
|
+
raise NotFound.new(program) unless location
|
69
|
+
location
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Make the actual test if a given path points to an executable file.
|
75
|
+
#
|
76
|
+
# @param [String] path is the absolute path to test
|
77
|
+
# @return [Boolean] whether the path is an executable file
|
78
|
+
def exists?(path)
|
79
|
+
@exists[path]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Subtrigger
|
2
|
+
# A simple wrapper around the output of Subversion's <tt>svnlook</tt>
|
3
|
+
# command.
|
4
|
+
#
|
5
|
+
# This class will let you make simple queries against the properties of a
|
6
|
+
# Subversion revision. It parses its output into keys and values so you can
|
7
|
+
# perform operations on them.
|
8
|
+
#
|
9
|
+
# == Attributes
|
10
|
+
#
|
11
|
+
# It knows about the following attributes:
|
12
|
+
#
|
13
|
+
# * Revision number
|
14
|
+
# * Author
|
15
|
+
# * Timestamp
|
16
|
+
# * Log message
|
17
|
+
# * changed directories
|
18
|
+
#
|
19
|
+
# This works by passing in the number of the revision to use, the raw
|
20
|
+
# output of <tt>svnlook info</tt> and the raw output of
|
21
|
+
# <tt>svnlook dirs-changed</tt>.
|
22
|
+
#
|
23
|
+
# == Special attributes
|
24
|
+
#
|
25
|
+
# Revision knows about changed projects. This is extracted from the list
|
26
|
+
# of changed directories. A project is a directory that is directly above
|
27
|
+
# a directory named <tt>trunk</tt>, <tt>branches</tt> or <tt>tags</tt>. So
|
28
|
+
# when a directory <tt>/internal/accounting/trunk</tt> is changed, the
|
29
|
+
# project <tt>/internal/accounting</tt> is reported.
|
30
|
+
#
|
31
|
+
# @example Example of raw input for <tt>info</tt>
|
32
|
+
# john
|
33
|
+
# 2010-07-05 17:00:00 +0200 (Mon, 01 Jan 2010)
|
34
|
+
# 215
|
35
|
+
# Description of log
|
36
|
+
#
|
37
|
+
# @example Usage
|
38
|
+
# @revision = Revision.new('...')
|
39
|
+
# @revision.author # => 'john'
|
40
|
+
# @revision.message # => 'Description of log'
|
41
|
+
# @revision.date # => (instance of Time)
|
42
|
+
# @revision.projects # => ['/project1', 'project2', ...]
|
43
|
+
#
|
44
|
+
# @author Arjan van der Gaag
|
45
|
+
# @since 0.3.0
|
46
|
+
class Revision
|
47
|
+
# The raw output of the svnlook command.
|
48
|
+
attr_reader :raw
|
49
|
+
|
50
|
+
# A list of all directories that were changed in this revision
|
51
|
+
attr_reader :dirs_changed
|
52
|
+
|
53
|
+
# the parsed Hash of attributes for this revision
|
54
|
+
attr_reader :attributes
|
55
|
+
|
56
|
+
def initialize(revision_number, info, dirs_changed)
|
57
|
+
@attributes = { :number => revision_number.to_i }
|
58
|
+
@raw = info
|
59
|
+
@dirs_changed = dirs_changed.split
|
60
|
+
parse
|
61
|
+
end
|
62
|
+
|
63
|
+
%w{author date message number}.each do |name|
|
64
|
+
define_method(name) do
|
65
|
+
attributes[name.to_sym]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates a list of directory paths in the repository that have changes
|
70
|
+
# and contain a <tt>trunk</tt>, <tt>branches</tt> or <tt>tags</tt>
|
71
|
+
# directory.
|
72
|
+
#
|
73
|
+
# For example, a changed path in like <tt>/topdir/project_name/trunk</tt>
|
74
|
+
# would result in <tt>/topdir/project_name</tt>.
|
75
|
+
#
|
76
|
+
# @return [Array<String>] list of changed project paths
|
77
|
+
def projects
|
78
|
+
pattern = /\/(trunk|branches|tags)/
|
79
|
+
dirs_changed.grep(pattern).map do |dir|
|
80
|
+
dir.split(pattern, 2).first
|
81
|
+
end.uniq
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Parses the raw log of svnlook into a Hash of attributes.
|
87
|
+
def parse
|
88
|
+
raise ArgumentError, 'Could not parse Subversion info: expected at least 4 lines' if raw.split("\n").size < 4
|
89
|
+
author, timestamp, size, message = raw.split("\n", 4)
|
90
|
+
attributes[:author] = author
|
91
|
+
attributes[:date] = Time.parse(timestamp)
|
92
|
+
attributes[:message] = message.chomp
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
module Subtrigger
|
2
|
+
# A <tt>Rule</tt> object knows when to fire some kind of action for some
|
3
|
+
# kind of revision. When the Subversion hook is fired, a Rule can inspect it
|
4
|
+
# and choose whether or not to fire its trigger (a piece code defined by the
|
5
|
+
# user).
|
6
|
+
#
|
7
|
+
# In the first example, the rule will output <tt>fired</tt> whenever a
|
8
|
+
# <tt>Revision</tt> comes along with a message containing <tt>foo</tt>.
|
9
|
+
#
|
10
|
+
# In the second example, we find all applicable rules for a given
|
11
|
+
# <tt>Revision</tt> object. We can then run each of them.
|
12
|
+
#
|
13
|
+
# @example 1: Define a simple Rule
|
14
|
+
# Rule.new(/foo/) { puts 'fired' }
|
15
|
+
#
|
16
|
+
# @example 2: Finding and firing Rules
|
17
|
+
# rev = Revision.new
|
18
|
+
# Rule.matching(rev).map { |rule| rule.run(rev) }
|
19
|
+
#
|
20
|
+
# @since 0.3.0
|
21
|
+
# @author Arjan van der Gaag
|
22
|
+
class Rule
|
23
|
+
|
24
|
+
# Exception for when trying to apply a rule to something other than an
|
25
|
+
# instance of Revision.
|
26
|
+
CannotCompare = Class.new(Exception)
|
27
|
+
|
28
|
+
# A hash of Revision attributes and regular expressions to match against
|
29
|
+
attr_reader :criteria
|
30
|
+
|
31
|
+
# The callback to run on a match
|
32
|
+
attr_reader :block
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
@rules = []
|
37
|
+
|
38
|
+
# Keep track of Rule objects that are created in a class instance variable
|
39
|
+
#
|
40
|
+
# @param [Rule] child is the new Rule object
|
41
|
+
# @return [Array<Rule>] the total list of children
|
42
|
+
def self.register(child)
|
43
|
+
@rules << child
|
44
|
+
end
|
45
|
+
|
46
|
+
public
|
47
|
+
|
48
|
+
# Return an array of all rules currently defined.
|
49
|
+
#
|
50
|
+
# @return [Array<Rule>]
|
51
|
+
def self.rules
|
52
|
+
@rules
|
53
|
+
end
|
54
|
+
|
55
|
+
# Reset the list of known rules, deleting all currently known rules.
|
56
|
+
#
|
57
|
+
# @return nil
|
58
|
+
def self.reset
|
59
|
+
@rules = []
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return an array of all existing Rule objects that match the given
|
63
|
+
# revision.
|
64
|
+
#
|
65
|
+
# @param [Revision] revision is the revision to compare rules to.
|
66
|
+
# @return [Array<Rule>] list of all matching rules
|
67
|
+
def self.matching(revision)
|
68
|
+
@rules.select { |child| child === revision }
|
69
|
+
end
|
70
|
+
|
71
|
+
# Create a new Rule object with criteria for different properties of a
|
72
|
+
# Revision. The required block defines the callback to run. It will have
|
73
|
+
# the current Revision object yielded to it.
|
74
|
+
#
|
75
|
+
# Criteria are Ruby objects that should match (`===`) a Revision's
|
76
|
+
# attributes. These would usually be regular expressions, but they
|
77
|
+
# can be strings or custom objects if you want to.
|
78
|
+
#
|
79
|
+
# @overload initialize(pattern, &block)
|
80
|
+
# Define a rule with a pattern matching the log message
|
81
|
+
# @param [Regex] pattern is the regular expression to match against
|
82
|
+
# the revision's log message
|
83
|
+
# @overload initialize(options, &block)
|
84
|
+
# Define a rule with various criteria in a hash.
|
85
|
+
# @param [Hash] options defines matching criteria.
|
86
|
+
# @option options :author Criterium for Revision#author
|
87
|
+
# @option options :date Criterium for Revision#date
|
88
|
+
# @option options :number Criterium for Revision#number
|
89
|
+
# @option options :project Criterium for Revision#project
|
90
|
+
def initialize(pattern_or_options, &block)
|
91
|
+
raise ArgumentError, 'a Rule requires a block' unless block_given?
|
92
|
+
|
93
|
+
# If not given a hash, we build a hash defaulting on message
|
94
|
+
unless pattern_or_options.is_a?(Hash)
|
95
|
+
pattern_or_options = { :message => pattern_or_options }
|
96
|
+
end
|
97
|
+
|
98
|
+
@criteria, @block = pattern_or_options, block
|
99
|
+
@criteria.inspect
|
100
|
+
self.class.register self
|
101
|
+
end
|
102
|
+
|
103
|
+
# Call this Rule's callback method with the give Revision object.
|
104
|
+
# @return [nil]
|
105
|
+
def run(rev)
|
106
|
+
@rev = rev
|
107
|
+
block.call(@rev, collect_captures)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Use {Rule#matches?} to see if this <tt>Rule</tt> matches the given
|
111
|
+
# <tt>Revision</tt>.
|
112
|
+
#
|
113
|
+
# @param [Object] the object to compare to
|
114
|
+
# @return [Boolean]
|
115
|
+
# @see Rule#matches?
|
116
|
+
def ===(other)
|
117
|
+
matches?(other)
|
118
|
+
rescue CannotCompare
|
119
|
+
super
|
120
|
+
end
|
121
|
+
|
122
|
+
# See if the current rule matches a given subversion revision.
|
123
|
+
#
|
124
|
+
# @param [Revision] revision the Revision object to compare to.
|
125
|
+
# @return [Boolean]
|
126
|
+
# @see Rule#===
|
127
|
+
# @raise Subtrigger::Rule::CannotCompare when comparing to something other
|
128
|
+
# than a revision.
|
129
|
+
def matches?(revision)
|
130
|
+
raise CannotCompare unless @criteria.keys.all? { |k| k == :all || revision.respond_to?(k) }
|
131
|
+
match = @criteria.any?
|
132
|
+
@criteria.each_pair do |key, value|
|
133
|
+
if key == :all
|
134
|
+
match = (value === revision)
|
135
|
+
else
|
136
|
+
match &= (value === revision.send(key.to_sym))
|
137
|
+
end
|
138
|
+
end
|
139
|
+
match
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
# When using regular expressions to match against string values, we
|
145
|
+
# want to be able to get to any captured groups. This method scans all
|
146
|
+
# string values with their Regex matchers and collects all captured
|
147
|
+
# groups into a namespaced hash.
|
148
|
+
#
|
149
|
+
# @example
|
150
|
+
# Rule.new /hello, (.+)!/ do |revision, matches|
|
151
|
+
# puts matches.inspect
|
152
|
+
# end
|
153
|
+
# # => { :message => ['world'] }
|
154
|
+
#
|
155
|
+
# @return [Hash] all captured groups per Revision attribute tested
|
156
|
+
# @todo this only passes on capture groups, not the entire match ($&)
|
157
|
+
def collect_captures
|
158
|
+
criteria.inject({}) do |output, (key, value)|
|
159
|
+
next if key == :all
|
160
|
+
output[key] = @rev.send(key.to_sym).scan(value).flatten if value.is_a?(Regexp)
|
161
|
+
output
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Subtrigger
|
2
|
+
# Reads, parses and manages inline templates.
|
3
|
+
#
|
4
|
+
# When you define string templates at the end of your rules file, this class
|
5
|
+
# can parse and keep track of them. You can then easily retrieve them again
|
6
|
+
# and optionally format it like with <tt>String#%</tt>.
|
7
|
+
#
|
8
|
+
# You simply define a new template using <tt>@@</tt>, followed by a name and
|
9
|
+
# then the textual contents (see the example below).
|
10
|
+
#
|
11
|
+
# You can read the templates and use them, for example, in e-mails.
|
12
|
+
#
|
13
|
+
# @example Defining templates
|
14
|
+
# # at the end of your Ruby file:
|
15
|
+
# __END__
|
16
|
+
# @@ Template 1
|
17
|
+
# Foo
|
18
|
+
# @@ Template 2
|
19
|
+
# Hello, %s!
|
20
|
+
#
|
21
|
+
# @example Parsing templates
|
22
|
+
# Template.parse(__DATA__.read)
|
23
|
+
#
|
24
|
+
# @example Using templates
|
25
|
+
# Template.find('Template 1') # => 'Foo'
|
26
|
+
#
|
27
|
+
# @example Formatting templates
|
28
|
+
# Template.find('Template 2') # => 'Hello, %s!'
|
29
|
+
# Template.find('Template 2').format('world') # => 'Hello, world!'
|
30
|
+
#
|
31
|
+
# @author Arjan van der Gaag
|
32
|
+
# @since 0.3.0
|
33
|
+
class Template
|
34
|
+
# The unique identifier for this template
|
35
|
+
attr_reader :name
|
36
|
+
|
37
|
+
# The actual contents of the template
|
38
|
+
attr_reader :string
|
39
|
+
|
40
|
+
# List of defined templates the class tracks
|
41
|
+
@children = []
|
42
|
+
|
43
|
+
# The pattern that separates one template from another
|
44
|
+
TEMPLATE_DELIMITER = /^@@ (.*)\n/
|
45
|
+
|
46
|
+
# Exception raised when a string cannot be parsed into templates,
|
47
|
+
# because the delimiter cannot be found
|
48
|
+
Unparseable = Class.new(Exception)
|
49
|
+
|
50
|
+
# Parse the contents of a string and extract templates from it. These are
|
51
|
+
# tracked so you can use {Template#find} to retrieve them by name.
|
52
|
+
#
|
53
|
+
# @param [String] the contents of your rules file's <tt>__DATA__.read</tt>
|
54
|
+
# @return [nil]
|
55
|
+
def self.parse(string)
|
56
|
+
raise Unparseable, "Could not split into templates: #{string.inspect}" unless string =~ TEMPLATE_DELIMITER
|
57
|
+
string.split(TEMPLATE_DELIMITER).map(&:chomp).slice(1..-1).each_slice(2) do |name, content|
|
58
|
+
@children << new(name, content)
|
59
|
+
end
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Finds and returns the content of the template by the given name.
|
64
|
+
#
|
65
|
+
# @param [String] name is the name of the template
|
66
|
+
# @return [String] is Template#content
|
67
|
+
def self.find(name)
|
68
|
+
@children.find { |child|
|
69
|
+
child.name == name
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
# Convert to string using the textual contents of the template
|
74
|
+
# @return [String]
|
75
|
+
def to_s
|
76
|
+
string
|
77
|
+
end
|
78
|
+
|
79
|
+
# Get the contents of the template and interpolate any given
|
80
|
+
# arguments into it.
|
81
|
+
#
|
82
|
+
# @example Getting a template and using interpolation
|
83
|
+
# template.to_s # => 'Dear %s...'
|
84
|
+
# template.format 'John' # => 'Dear John...'
|
85
|
+
# @return [String] the formatted template contents
|
86
|
+
def format(*args)
|
87
|
+
to_s % [*args]
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param [String] name is the unique identifier of a template
|
91
|
+
# @param [String] string is the contents of the template.
|
92
|
+
def initialize(name, string)
|
93
|
+
@name, @string = name, string
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/subtrigger.gemspec
CHANGED
@@ -5,65 +5,65 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{subtrigger}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Arjan van der Gaag"]
|
12
|
-
s.date = %q{2010-
|
13
|
-
s.default_executable = %q{subtrigger}
|
12
|
+
s.date = %q{2010-07-16}
|
14
13
|
s.description = %q{This gem allows you to create simple Ruby triggers for Subversion commit messages, responding to keywords in your log messages to send e-mails, deploy sites or do whatever you need.}
|
15
14
|
s.email = %q{arjan@arjanvandergaag.nl}
|
16
|
-
s.executables = ["subtrigger"]
|
17
15
|
s.extra_rdoc_files = [
|
18
|
-
"
|
19
|
-
"README.rdoc"
|
16
|
+
"README.md"
|
20
17
|
]
|
21
18
|
s.files = [
|
22
19
|
".document",
|
23
20
|
".gitignore",
|
24
|
-
"
|
25
|
-
"README.rdoc",
|
21
|
+
"README.md",
|
26
22
|
"Rakefile",
|
27
23
|
"VERSION",
|
28
|
-
"bin/subtrigger",
|
29
24
|
"lib/subtrigger.rb",
|
30
|
-
"lib/subtrigger/
|
31
|
-
"lib/subtrigger/
|
32
|
-
"lib/subtrigger/
|
25
|
+
"lib/subtrigger/dsl.rb",
|
26
|
+
"lib/subtrigger/path.rb",
|
27
|
+
"lib/subtrigger/revision.rb",
|
28
|
+
"lib/subtrigger/rule.rb",
|
29
|
+
"lib/subtrigger/template.rb",
|
33
30
|
"subtrigger.gemspec",
|
34
|
-
"test/
|
35
|
-
"test/
|
36
|
-
"test/
|
37
|
-
"test/
|
38
|
-
"test/
|
31
|
+
"test/test_helper.rb",
|
32
|
+
"test/test_path.rb",
|
33
|
+
"test/test_revision.rb",
|
34
|
+
"test/test_rule.rb",
|
35
|
+
"test/test_template.rb"
|
39
36
|
]
|
40
37
|
s.homepage = %q{http://github.com/avdgaag/subtrigger}
|
41
38
|
s.rdoc_options = ["--charset=UTF-8"]
|
42
39
|
s.require_paths = ["lib"]
|
43
|
-
s.rubygems_version = %q{1.3.
|
40
|
+
s.rubygems_version = %q{1.3.7}
|
44
41
|
s.summary = %q{Create post-commit triggers for Subversion commit messages}
|
45
42
|
s.test_files = [
|
46
|
-
"test/
|
47
|
-
"test/
|
48
|
-
"test/
|
49
|
-
"test/
|
50
|
-
"test/
|
43
|
+
"test/test_helper.rb",
|
44
|
+
"test/test_path.rb",
|
45
|
+
"test/test_revision.rb",
|
46
|
+
"test/test_rule.rb",
|
47
|
+
"test/test_template.rb"
|
51
48
|
]
|
52
49
|
|
53
50
|
if s.respond_to? :specification_version then
|
54
51
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
55
52
|
s.specification_version = 3
|
56
53
|
|
57
|
-
if Gem::Version.new(Gem::
|
54
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
58
55
|
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
59
56
|
s.add_development_dependency(%q<mocha>, [">= 0"])
|
57
|
+
s.add_runtime_dependency(%q<pony>, [">= 0"])
|
60
58
|
else
|
61
59
|
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
62
60
|
s.add_dependency(%q<mocha>, [">= 0"])
|
61
|
+
s.add_dependency(%q<pony>, [">= 0"])
|
63
62
|
end
|
64
63
|
else
|
65
64
|
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
66
65
|
s.add_dependency(%q<mocha>, [">= 0"])
|
66
|
+
s.add_dependency(%q<pony>, [">= 0"])
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|