dryft 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.
- 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
|
+
|