dryft 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.txt +21 -0
- data/README.rdoc +112 -0
- data/Rakefile +2 -0
- data/bin/dryft +6 -0
- data/dryft.gemspec +24 -0
- data/lib/dryft.rb +13 -0
- data/lib/dryft/job.rb +126 -0
- data/lib/dryft/jobs.rb +63 -0
- data/lib/dryft/version.rb +3 -0
- data/lib/nokogiri/node.rb +32 -0
- data/lib/nokogiri/node_set.rb +13 -0
- data/lib/ruby/object.rb +11 -0
- metadata +111 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
dryft (0.0.1)
|
5
|
+
nokogiri
|
6
|
+
sqlite3-ruby
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
nokogiri (1.4.4)
|
12
|
+
sqlite3 (1.3.3)
|
13
|
+
sqlite3-ruby (1.3.3)
|
14
|
+
sqlite3 (>= 1.3.3)
|
15
|
+
|
16
|
+
PLATFORMS
|
17
|
+
ruby
|
18
|
+
|
19
|
+
DEPENDENCIES
|
20
|
+
dryft!
|
21
|
+
nokogiri
|
22
|
+
sqlite3-ruby
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2011 Chris Berkhout (http://chrisberkhout.com)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
= DRYFT for WinAutomation
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
DRYFT (Don't Repeat Yourself Factoring Tool) lets you define procedures in
|
6
|
+
WinAutomation[http://www.winautomation.com/] that can be included in multiple
|
7
|
+
other places and easily maintained from their original definition locations
|
8
|
+
without introducing consistency issues.
|
9
|
+
|
10
|
+
== Installation
|
11
|
+
|
12
|
+
1. Install Ruby 1.8.7 with
|
13
|
+
{RubyInstaller for Windows}[http://rubyinstaller.org].
|
14
|
+
2. Run <tt>gem install dryft</tt>.
|
15
|
+
3. Complete any additional setup for the <tt>sqlite3-ruby</tt> gem.
|
16
|
+
|
17
|
+
== Conventions for procedures
|
18
|
+
|
19
|
+
A procedure is a WinAutomation job that follows DRYFT conventions, and can
|
20
|
+
therefore have DRYFT manage its dependencies on other procedures.
|
21
|
+
|
22
|
+
=== Creating a procedure
|
23
|
+
|
24
|
+
To create a procedure, create a job with a name enclosed in angle brackets: e.g.
|
25
|
+
<tt><your procedure name></tt>. Extra text may follow the closing bracket and
|
26
|
+
will not be considered part of the procedure name, however, the opening bracket
|
27
|
+
must be the first character of the job name.
|
28
|
+
|
29
|
+
DRYFT ignores any jobs that do not follow the procedure naming convention. Only
|
30
|
+
proper procedures can include other procedures.
|
31
|
+
|
32
|
+
=== Defining the steps of a procedure
|
33
|
+
|
34
|
+
Inside the job, start the procedure definition with a comment step starting:
|
35
|
+
<tt><your procedure name></tt>. The procedure name must be at the start of the
|
36
|
+
comment, but may be followed by other text. This is the opening tag.
|
37
|
+
|
38
|
+
After that, add another comment step that has the procedure name with a
|
39
|
+
forward-slash following the opening angle bracket:
|
40
|
+
<tt></your procedure name></tt>. This is the closing tag.
|
41
|
+
|
42
|
+
Any steps you place between the opening and closing tags will be considered part
|
43
|
+
of the procedure definition and will be copied to wherever the procedure is used
|
44
|
+
in other procedures. Any steps before the opening tag or after the closing tag
|
45
|
+
will not be copyed.
|
46
|
+
|
47
|
+
This means that you can use steps outside of the definition to help you make the
|
48
|
+
procedure definition job run by itself. For example, you may have a large
|
49
|
+
procedure that dynamically sets up certain configuration variables before
|
50
|
+
calling a smaller procedure. In the job defining the smaller procedure you can
|
51
|
+
hard-code the configuration variables before the opening tag so that that job can
|
52
|
+
be run by itself.
|
53
|
+
|
54
|
+
Similarly, steps after the closing tag can be used to provide feedback that is
|
55
|
+
helpful when running the procedure definition job individually, but which
|
56
|
+
shouldn't be included when the procedure is used within a larger one.
|
57
|
+
|
58
|
+
=== Using a procedure in other procedures
|
59
|
+
|
60
|
+
To use one procedure within another, copy the steps from the opening tag to the
|
61
|
+
closing tag in the source procedure, and paste them into the destination
|
62
|
+
procedure wherever you want them to run.
|
63
|
+
|
64
|
+
=== Updating a procedure automatically
|
65
|
+
|
66
|
+
Now, if you make some changes to the procedure in its defining job, you can
|
67
|
+
run DRYFT to automatically copy those changes across to wherever that procedure
|
68
|
+
is used in others. Be aware that if you change the steps between a procedures
|
69
|
+
opening and closing tags in a job that uses it (rather than defines it), DRYFT
|
70
|
+
will overwrite those changes with the old steps from the original procedure
|
71
|
+
definition job.
|
72
|
+
|
73
|
+
A procedure can include multiple other procedures and they can be nested to any
|
74
|
+
depth. DRYFT resovles dependencies so that any given procedure will only ever be
|
75
|
+
updated after all of its dependencies have been updated. It will detect improper
|
76
|
+
use of opening and closing tags and generate appropriate error messages. For
|
77
|
+
example, it will report unbalanced tags, use of undefined procedures and
|
78
|
+
circular dependencies.
|
79
|
+
|
80
|
+
When using the WinAutomation console, it is necessary to press F5 to refresh
|
81
|
+
the job list after DRYFT performs updates. This is because updated jobs are
|
82
|
+
assigned new IDs as a way of forcing the WinAutomation to disregard its old copy
|
83
|
+
of the job code.
|
84
|
+
|
85
|
+
=== In conclusion
|
86
|
+
|
87
|
+
Go ahead and define procedures as you please, maintain them from their original
|
88
|
+
definition jobs and run DRYFT (and refresh with F5) often to ensure your jobs
|
89
|
+
database is consistent.
|
90
|
+
|
91
|
+
== Usage
|
92
|
+
|
93
|
+
To run load and update the default WinAutomation jobs database:
|
94
|
+
dryft
|
95
|
+
|
96
|
+
To load and update a WinAutomation jobs database in a different location:
|
97
|
+
dryft \path\to\your\Jobs.dat
|
98
|
+
|
99
|
+
== Compatibility
|
100
|
+
|
101
|
+
DRYFT has been developed using WinAutomation version 3.1.4.628 (released
|
102
|
+
December 17, 2010). It may work on earlier versions and will probably work
|
103
|
+
on later 3.1.x versions.
|
104
|
+
|
105
|
+
== Copyright
|
106
|
+
|
107
|
+
DRYFT comes to you under the MIT license. See LICENSE.txt for details.
|
108
|
+
|
109
|
+
== Feedback
|
110
|
+
|
111
|
+
I would love to hear any feedback you have about DRYFT!
|
112
|
+
The best way to reach me is via email at gmail.com (chrisberkhout@).
|
data/Rakefile
ADDED
data/bin/dryft
ADDED
data/dryft.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "dryft/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "dryft"
|
7
|
+
s.version = Dryft::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Chris Berkhout"]
|
10
|
+
s.email = ["chrisberkhout@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/chrisberkhout/dryft"
|
12
|
+
s.summary = %q{Don't Repeat Yoursef Factoring Tool for WinAutomation}
|
13
|
+
s.description = %q{Define WinAutomation procedures that can be included elsewhere without consistency issues.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "dryft"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency("sqlite3-ruby")
|
23
|
+
s.add_dependency("nokogiri")
|
24
|
+
end
|
data/lib/dryft.rb
ADDED
data/lib/dryft/job.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
module DRYFT
|
2
|
+
class Job
|
3
|
+
|
4
|
+
attr_reader :id, :name, :proc, :def_acts, :deps
|
5
|
+
|
6
|
+
def initialize(db, info)
|
7
|
+
@db = db
|
8
|
+
@id = get_id(db, info)
|
9
|
+
load
|
10
|
+
end
|
11
|
+
|
12
|
+
def reload
|
13
|
+
load
|
14
|
+
end
|
15
|
+
|
16
|
+
def update_from_deps(jobs)
|
17
|
+
no_change = true
|
18
|
+
@deps.each do |dep|
|
19
|
+
src_job = jobs.by_proc(dep[:proc])
|
20
|
+
if dep[:acts].not_equivalent_to?( src_job.def_acts )
|
21
|
+
no_change = false
|
22
|
+
dep[:acts].after( src_job.def_acts.to_xml )
|
23
|
+
dep[:acts].unlink
|
24
|
+
puts "At #{@name}:#{dep[:start]}, updated procedure <#{dep[:proc]}> from its definition."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
if no_change
|
28
|
+
puts "No change to '#{@name}'."
|
29
|
+
else
|
30
|
+
updated_code = @doc.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
|
31
|
+
@db.execute("UPDATE jobcode SET code = ? WHERE hex(id) = ?", [updated_code, @id])
|
32
|
+
|
33
|
+
# Switch to a new job ID, because there is no way to trigger a reload ov the original job ID's code.
|
34
|
+
new_id = @db.execute("SELECT HEX(RANDOMBLOB(LENGTH(Id))) FROM jobcode")[0][0]
|
35
|
+
@db.execute("UPDATE compilerproperties SET JobId = x'#{new_id}' WHERE hex(JobId) = ?", [@id])
|
36
|
+
@db.execute("UPDATE jobaddon SET JobId = x'#{new_id}' WHERE hex(JobId) = ?", [@id])
|
37
|
+
@db.execute("UPDATE jobaddonassembly SET JobId = x'#{new_id}' WHERE hex(JobId) = ?", [@id])
|
38
|
+
@db.execute("UPDATE jobattachment SET JobId = x'#{new_id}' WHERE hex(JobId) = ?", [@id])
|
39
|
+
@db.execute("UPDATE jobcode SET Id = x'#{new_id}' WHERE hex(Id) = ?", [@id])
|
40
|
+
@db.execute("UPDATE jobinfo SET Id = x'#{new_id}' WHERE hex(Id) = ?", [@id])
|
41
|
+
@db.execute("UPDATE jobproperties SET Id = x'#{new_id}' WHERE hex(Id) = ?", [@id])
|
42
|
+
@db.execute("UPDATE jobproperties2 SET Id = x'#{new_id}' WHERE hex(Id) = ?", [@id])
|
43
|
+
@db.execute("UPDATE triggers SET JobId = x'#{new_id}' WHERE hex(JobId) = ?", [@id])
|
44
|
+
@id = new_id
|
45
|
+
|
46
|
+
reload
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def get_id(db, info)
|
53
|
+
case info.keys[0]
|
54
|
+
when :id
|
55
|
+
info[:id]
|
56
|
+
when :name
|
57
|
+
rows = db.execute("SELECT hex(id) FROM jobinfo WHERE name = ?", [info[:name]])
|
58
|
+
abort "ERROR: tried to load the job named '#{info[:name]}', but that name is not unique." if rows.length > 1
|
59
|
+
abort "ERROR: tried to load the job named '#{info[:name]}', but it was not found." if rows.length == 0
|
60
|
+
rows[0][0]
|
61
|
+
when :proc
|
62
|
+
rows = db.execute("SELECT hex(id) FROM jobinfo WHERE name LIKE ?", ["<#{info[:proc]}>%"])
|
63
|
+
abort "ERROR: tried to load the procedure named '#{info[:proc]}', but that name is not unique." if rows.length > 1
|
64
|
+
abort "ERROR: tried to load the procedure named '#{info[:proc]}', but it was not found." if rows.length == 0
|
65
|
+
rows[0][0]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def load
|
70
|
+
rows = @db.execute("SELECT hex(i.id), i.name, c.code FROM jobinfo i, jobcode c WHERE i.id = c.id AND hex(i.id) = ?", [@id])
|
71
|
+
abort "ERROR: tried to load the job with ID '#{@id}', but it was not found." if rows.length == 0
|
72
|
+
@id, @name, @code = rows[0]
|
73
|
+
if @name =~ /^\<([^\/\>].*?)\>.*/
|
74
|
+
@proc = $1
|
75
|
+
else
|
76
|
+
abort "ERROR: tried to initialise a job ('#{@name}') that is not a procedure."
|
77
|
+
end
|
78
|
+
parse
|
79
|
+
end
|
80
|
+
|
81
|
+
def parse
|
82
|
+
@actions = nil
|
83
|
+
@def_acts = nil
|
84
|
+
@deps = []
|
85
|
+
stack = []
|
86
|
+
def_start = nil
|
87
|
+
def_end = nil
|
88
|
+
|
89
|
+
@doc = Nokogiri::XML(@code)
|
90
|
+
@actions = @doc.xpath("//xmlns:ActionFlow[@Name='Main Flow']/*")
|
91
|
+
@actions.each_with_index do |a,i|
|
92
|
+
|
93
|
+
comment = a.xpath("./descendant-or-self::xmlns:CommentAction/xmlns:Comment").first
|
94
|
+
if comment && comment.inner_text =~ /^\<([^\/\>].*?)\>.*/ # opening tag
|
95
|
+
|
96
|
+
tag = $1
|
97
|
+
abort "ERROR: at '#{@name}:#{i+1}', attempt to define <#{@proc}> within <#{stack.last[:tag]}>." if tag == @proc && stack.length > 0
|
98
|
+
abort "ERROR: at '#{@name}:#{i+1}', reopening <#{tag}> here implies circular dependency." if tag.is_in? stack.map{ |e| e[:tag] }
|
99
|
+
stack.push({:tag => tag, :start => (i+1) })
|
100
|
+
|
101
|
+
elsif comment && comment.inner_text =~ /^\<\/(.*?)\>.*/ # closing tag
|
102
|
+
|
103
|
+
tag = $1
|
104
|
+
abort "ERROR: at '#{name}:#{i+1}', attempt to close <#{tag}> when nothing was open." if stack.length == 0
|
105
|
+
abort "ERROR: at '#{name}:#{i+1}', attempt to close <#{tag}> when close of <#{stack.last[:tag]}> was expected." if stack.last[:tag] != tag
|
106
|
+
if tag == @proc # end of definition of the procedure
|
107
|
+
def_start = stack.last[:start]
|
108
|
+
def_end = i+1
|
109
|
+
elsif stack.length == 1 || stack[-2][:tag] == @proc # end of definition of a direct dependency
|
110
|
+
@deps.push({ :proc => tag, :start => stack.last[:start], :end => i+1, :acts => @actions[(stack.last[:start]-1)..(i)] })
|
111
|
+
end
|
112
|
+
stack.pop
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end # each action
|
117
|
+
|
118
|
+
abort "ERROR: in '#{@name}', there was no code to define the procedure <#{@proc}>." if def_start.nil?
|
119
|
+
abort "ERROR: in '#{@name}', no closing tag for the definition of <#{@proc}>." if def_end.nil?
|
120
|
+
abort "ERROR: in '#{@name}', the following tags were not closed: <#{stack.map{ |e| e[:tag] }.join('>, <')}>." if stack.length > 0
|
121
|
+
|
122
|
+
@def_acts = @actions[ (def_start-1) .. (def_end-1) ]
|
123
|
+
end # parse
|
124
|
+
|
125
|
+
end
|
126
|
+
end # module
|
data/lib/dryft/jobs.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module DRYFT
|
2
|
+
class Jobs
|
3
|
+
|
4
|
+
def initialize(db_file)
|
5
|
+
abort "ERROR: The specified WinAutomation jobs database does not exist: #{db_file}" if !File.exists?(db_file)
|
6
|
+
@job_list = get_jobs(SQLite3::Database.new db_file)
|
7
|
+
puts "Loaded the WinAutomation jobs database from: #{db_file}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def by_id(id)
|
11
|
+
(@job_list.select{ |j| j.id == id }).first
|
12
|
+
end
|
13
|
+
def by_name(name)
|
14
|
+
(@job_list.select{ |j| j.name == name }).first
|
15
|
+
end
|
16
|
+
def by_proc(proc)
|
17
|
+
(@job_list.select{ |j| j.proc == proc }).first
|
18
|
+
end
|
19
|
+
|
20
|
+
def update_all
|
21
|
+
resolve_list(@job_list).each do |j|
|
22
|
+
j.update_from_deps(self)
|
23
|
+
end
|
24
|
+
puts "Updated all procedures.\n\n"
|
25
|
+
puts "Please PRESS F5 in the WinAutomation Console to refresh the jobs list!"
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def get_jobs(db)
|
31
|
+
jobs = []
|
32
|
+
rows = db.execute("SELECT hex(id) FROM jobinfo WHERE name LIKE '<%>%'")
|
33
|
+
rows.each do |r|
|
34
|
+
id = r[0]
|
35
|
+
jobs.push( Job.new(db, :id => id) )
|
36
|
+
end
|
37
|
+
jobs
|
38
|
+
end
|
39
|
+
|
40
|
+
def resolve_list(job_list)
|
41
|
+
resolved = []
|
42
|
+
job_list.each{ |j| resolved = resolve(j, resolved) }
|
43
|
+
resolved
|
44
|
+
end
|
45
|
+
|
46
|
+
def resolve(job, resolved = [], unresolved = [])
|
47
|
+
if job.not_in? resolved
|
48
|
+
unresolved << job
|
49
|
+
job.deps.each do |dep|
|
50
|
+
abort "ERROR: at '#{job.name}:#{dep[:start]}', the procedure <#{dep[:proc]}> is used but not defined." if by_proc(dep[:proc]).nil?
|
51
|
+
if by_proc(dep[:proc]).not_in? resolved
|
52
|
+
abort "ERROR: circular dependency detected: <#{job.proc}> -> <#{dep[:proc]}>." if by_proc(dep[:proc]).is_in? unresolved
|
53
|
+
resolved = resolve(by_proc(dep[:proc]), resolved, unresolved)
|
54
|
+
unresolved -= resolved
|
55
|
+
end
|
56
|
+
end
|
57
|
+
resolved << job
|
58
|
+
end
|
59
|
+
return resolved
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end # module
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Nokogiri::XML::Node
|
2
|
+
|
3
|
+
def equivalent_to?(other)
|
4
|
+
|
5
|
+
self_nodes = []
|
6
|
+
other_nodes = []
|
7
|
+
|
8
|
+
self.traverse { |n| self_nodes << n }
|
9
|
+
other.traverse { |n| other_nodes << n }
|
10
|
+
|
11
|
+
return false if self_nodes.length != other_nodes.length
|
12
|
+
|
13
|
+
0.upto(self_nodes.length-1) do |i|
|
14
|
+
|
15
|
+
s = self_nodes[i] ; s_attribs = {} ; s.attributes.each_pair { |k,v| s_attribs[k] = v.value }
|
16
|
+
o = other_nodes[i] ; o_attribs = {} ; o.attributes.each_pair { |k,v| o_attribs[k] = v.value }
|
17
|
+
|
18
|
+
return false if s.name != o.name
|
19
|
+
return false if ((s.text? || s.cdata?) && s.text) != ((o.text? || o.cdata?) && o.text)
|
20
|
+
return false if s_attribs != o_attribs
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
return true
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def not_equivalent_to?(other)
|
29
|
+
!equivalent_to?(other)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Nokogiri::XML::NodeSet
|
2
|
+
|
3
|
+
def equivalent_to?(other)
|
4
|
+
return false if self.length != other.length
|
5
|
+
0.upto(self.length-1) { |i| return false if self[i].not_equivalent_to?( other[i] ) }
|
6
|
+
return true
|
7
|
+
end
|
8
|
+
|
9
|
+
def not_equivalent_to?(other)
|
10
|
+
!equivalent_to?(other)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/lib/ruby/object.rb
ADDED
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dryft
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Chris Berkhout
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-20 00:00:00 +11:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: sqlite3-ruby
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: nokogiri
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
description: Define WinAutomation procedures that can be included elsewhere without consistency issues.
|
50
|
+
email:
|
51
|
+
- chrisberkhout@gmail.com
|
52
|
+
executables:
|
53
|
+
- dryft
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
files:
|
59
|
+
- .gitignore
|
60
|
+
- Gemfile
|
61
|
+
- Gemfile.lock
|
62
|
+
- LICENSE.txt
|
63
|
+
- README.rdoc
|
64
|
+
- Rakefile
|
65
|
+
- bin/dryft
|
66
|
+
- dryft.gemspec
|
67
|
+
- lib/.DS_Store
|
68
|
+
- lib/dryft.rb
|
69
|
+
- lib/dryft/job.rb
|
70
|
+
- lib/dryft/jobs.rb
|
71
|
+
- lib/dryft/version.rb
|
72
|
+
- lib/nokogiri/node.rb
|
73
|
+
- lib/nokogiri/node_set.rb
|
74
|
+
- lib/ruby/.DS_Store
|
75
|
+
- lib/ruby/object.rb
|
76
|
+
has_rdoc: true
|
77
|
+
homepage: http://github.com/chrisberkhout/dryft
|
78
|
+
licenses: []
|
79
|
+
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
hash: 3
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
hash: 3
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
requirements: []
|
104
|
+
|
105
|
+
rubyforge_project: dryft
|
106
|
+
rubygems_version: 1.3.7
|
107
|
+
signing_key:
|
108
|
+
specification_version: 3
|
109
|
+
summary: Don't Repeat Yoursef Factoring Tool for WinAutomation
|
110
|
+
test_files: []
|
111
|
+
|