ratch 0.1 → 0.2.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.
@@ -0,0 +1,56 @@
1
+
2
+ module Ratch
3
+
4
+ # No fuss access to ARGV. This shows up as #argv in the ratch api.
5
+ #
6
+ # Ratch uses '=' for parameterized flags b/c this make parsing stupid simple
7
+ # and that's a good thing!!!
8
+
9
+ module ArgvUtils
10
+
11
+ def argv
12
+ @argv ||= (ARGV.dup).extend(Ext)
13
+ end
14
+
15
+ module Ext
16
+
17
+ def flags
18
+ @flags ||= collect{ |e| e =~ /^-/ && e !~ /=/ }
19
+ end
20
+
21
+ def arguments
22
+ @arguments ||= collect{ |e| e !~ /=/ }
23
+ end
24
+
25
+ def parameters
26
+ @parameters ||= (
27
+ pms = {}
28
+ collect{ |e| e =~ /=/ }.each do |e|
29
+ pms.store(*split('='))
30
+ end
31
+ pms
32
+ )
33
+ end
34
+
35
+ # Does ARGV include a specifc flag?
36
+ def flag?(flag)
37
+ include?(flag)
38
+ end
39
+
40
+ # You can use this if you want to use parameterized
41
+ # flags w/o the '=', however be aware that the
42
+ # parameter value will also be listed amoung the
43
+ # bare arguments list. For example:
44
+ #
45
+ # $ foo tom --say hello
46
+ #
47
+ # argv.value('--say') #=> "hello"
48
+ # argv.arguments #=> ["tom", "hello"]
49
+ #
50
+ def value(flag)
51
+ fetch(index(flag)+1)
52
+ end
53
+
54
+ end
55
+ end
56
+ end
data/lib/ratch/batch.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  #require 'shellwords'
2
2
  require 'rbconfig' # replace with facets/rbsystem in future ?
3
3
  require 'ratch/taskutils'
4
+ require 'ratch/batchable'
4
5
 
5
6
  module Ratch
6
7
 
@@ -11,6 +12,9 @@ module Ratch
11
12
 
12
13
  include TaskUtils
13
14
 
15
+ include Batchable
16
+ include OpenBatchable
17
+
14
18
  # Quick start, equivalent to calling new.run(file).
15
19
 
16
20
  #def self.start(file)
@@ -29,7 +33,9 @@ module Ratch
29
33
  def call(arguments=nil)
30
34
  script = File.read($0 = @file)
31
35
  eval(script, binding, $0) #instance_eval(script)
32
- @main.call if @main
36
+ #@main.call if @main
37
+ task_manager.call_main
38
+ #run(:main) if task_manager.main
33
39
  end
34
40
 
35
41
  end
@@ -1,43 +1,66 @@
1
1
  module Ratch
2
2
 
3
- #
3
+ class BatchManager
4
4
 
5
- module Runnable
5
+ # Task cache, which prevents batch runs from re-executing.
6
+ attr :cache
6
7
 
7
- # TODO How to handle arguments?
8
+ # New BatchManager.
9
+ def initialize
10
+ @cache = {}
11
+ end
8
12
 
13
+ #
14
+ def batch(batchfile, arguments=nil)
15
+ @cache[batchfile] ||= run(batchfile, arguments)
16
+ end
17
+
18
+ # TODO How to handle arguments?
9
19
  def run(batchfile, arguments=nil)
10
20
  BatchFile.new(batchfile).call
11
- # # TODO probably should raise error instead
12
- # abort "missing batch file -- #{batchfile}" unless File.file?(batchfile)
13
- # script = File.read($0 = batchfile)
14
- # #instance_eval(script)
15
- # eval(script, binding, $0)
21
+ # # TODO probably should raise error instead
22
+ # abort "missing batch file -- #{batchfile}" unless File.file?(batchfile)
23
+ # script = File.read($0 = batchfile)
24
+ # #instance_eval(script)
25
+ # eval(script, binding, $0)
26
+ end
27
+
28
+ #
29
+ def done?(batchfile)
30
+ batchfile == $0 or @cache.key?(batchfile)
31
+ end
32
+
33
+ end
34
+
35
+ #
36
+
37
+ module Batchable
38
+
39
+ # Reference batch manager.
40
+ def batch_manager
41
+ @batch_manager ||= BatchManager.new
16
42
  end
17
43
 
18
44
  # Batch run, ie. run and cache.
19
45
  # Usually this can be take care of by method_missing.
20
46
  # But, in some cases, built in method names block task
21
47
  # calls, so you have to use #batch to invoke those.
22
-
23
48
  def batch(batchfile, arguments=nil)
24
- task_cache[task] ||= run(batchfile, arguments)
49
+ batch_manager.batch(batchfile, arguments=nil) # why did I have task instead of batchfile before?
25
50
  end
26
51
 
27
- # Task cache, which prevents batch runs from re-executing.
28
-
29
- def task_cache
30
- @@task_cache ||= {}
52
+ # Lauch a batch file (non-cached)
53
+ def launch(batchfile, arguments=nil)
54
+ batch_manager.run(batchfile, arguments=nil)
31
55
  end
32
56
 
33
- # Is a task complete or in the process of being completed?
34
-
35
- def done?(task)
36
- task == $0 or task_cache.key?(task)
57
+ # Is a batch run complete or in the process of being completed?
58
+ def done?(batchfile)
59
+ batch_manager.done?(batchfile)
37
60
  end
38
61
 
39
62
  # Shell runner.
40
-
63
+ # TODO Does this belong here?
41
64
  def sh(cmd)
42
65
  if noharm?
43
66
  puts cmd
@@ -49,16 +72,15 @@ module Ratch
49
72
  end
50
73
 
51
74
  # Abort running.
52
-
53
- def abort(msg=nil)
54
- puts msg if msg
55
- exit 0
56
- end
75
+ #def abort(msg=nil)
76
+ # puts msg if msg
77
+ # exit 0
78
+ #end
57
79
 
58
80
  end
59
81
 
60
82
  #
61
- module OpenRunnable
83
+ module OpenBatchable
62
84
 
63
85
  # If method is missing try to run an external task
64
86
  # or binary by that name. If it is a binary, arguments
@@ -106,8 +128,8 @@ module Ratch
106
128
  puts "--> #{cache ? '' : 'not-'}cached execution: #{cmd}" if trace?
107
129
  res = run(task, args)
108
130
  if cache
109
- #@task_cache[task] ||= (system(cmd); true)
110
- task_cache[task] ||= res
131
+ #@batch_catch[task] ||= (system(cmd); true)
132
+ batch_catch[task] ||= res
111
133
  end
112
134
  end
113
135
 
@@ -0,0 +1,107 @@
1
+ module Ratch
2
+
3
+ # = Buildable mixin
4
+ #
5
+ module Buildable
6
+
7
+ # Reference task manager.
8
+ def build_manager
9
+ @build_manager ||= BuildManager.new
10
+ end
11
+
12
+ # Define a build target.
13
+ def file(name, &block)
14
+ name, deps, block = *parse_build_dependencies(name, &block)
15
+ @build_manager.define_file(name, *deps, &block)
16
+ end
17
+
18
+ # Build a file.
19
+ def build(file)
20
+ @build_manager.call(file)
21
+ end
22
+
23
+ private
24
+
25
+ #
26
+ def parse_build_dependencies
27
+ if Hash===name_deps
28
+ name = name_deps.keys[0]
29
+ deps = name_deps.values[0]
30
+ else
31
+ name = name_deps
32
+ deps = []
33
+ end
34
+ [name, *deps, &block]
35
+ end
36
+ end
37
+
38
+ # = BuildManager class
39
+ #
40
+ class BuildManager
41
+ attr :builds
42
+
43
+ def initialize
44
+ @builds = {}
45
+ end
46
+
47
+ def define_file(name, *depend, &block)
48
+ build = Build.new(name, *depend, &block)
49
+ builds[build.name] = task
50
+ end
51
+
52
+ #
53
+ def call(file)
54
+ plan.each{ |name| @@tasks[name].action_call }
55
+ #action_call
56
+ end
57
+
58
+ # TODO Check for circular dependencies.
59
+ def plan(list=[])
60
+ if list.include?(name)
61
+ raise "Circular dependency #{name}."
62
+ end
63
+ @preqs.each do |need|
64
+ need = need.to_s
65
+ next if list.include?(need)
66
+ @@tasks[need].plan(list)
67
+ end
68
+ list << name
69
+ return list
70
+ end
71
+
72
+ end
73
+
74
+ # = Build class
75
+ #
76
+ class Build
77
+
78
+ attr :name
79
+ attr :preqs
80
+ attr :action
81
+
82
+ #
83
+ def initialize(name, *preqs, &action)
84
+ @name = name.to_s
85
+ @preqs = preqs
86
+ @action = action
87
+ end
88
+
89
+ #
90
+ def call
91
+ files = Dir.glob(@name)
92
+ files.each do |name|
93
+ if File.exist?(name)
94
+ mtime = File.mtime(name)
95
+ needs = @preqs.find do |file|
96
+ !File.exist?(file) || File.mtime(file) > mtime
97
+ end
98
+ else
99
+ needs = true
100
+ end
101
+ @action.call(@name) if needs
102
+ end
103
+ end
104
+
105
+ end
106
+ end
107
+
data/lib/ratch/options.rb CHANGED
@@ -5,7 +5,7 @@ module Ratch
5
5
 
6
6
  module GeneralOptions
7
7
 
8
- #
8
+ # Duplicate of ARGV.
9
9
 
10
10
  def argv
11
11
  @argv ||= ARGV.dup
@@ -1,105 +1,115 @@
1
1
  module Ratch
2
2
 
3
+ # = Taskable Mixin
4
+ #
3
5
  module Taskable
4
6
 
5
- #def main
6
- # @main
7
- #end
8
-
9
- def tasks
10
- @tasks ||= {}
7
+ # Reference task manager.
8
+ def task_manager
9
+ @task_manager ||= TaskManager.new
11
10
  end
12
11
 
13
12
  # Define a main task.
14
-
15
13
  def main(name, &block)
16
- @main = Task.register(name, &block)
17
- tasks[@main.name] = @main
14
+ name, deps, block = *parse_task_dependencies(name, &block)
15
+ task_manager.define_main(name, *deps, &block)
18
16
  end
19
17
 
20
18
  # Define a task.
21
-
22
19
  def task(name, &block)
23
- tsk = Task.register(name, &block)
24
- tasks[tsk.name] = tsk
20
+ name, deps, block = *parse_task_dependencies(name, &block)
21
+ task_manager.define_task(name, *deps, &block)
25
22
  end
26
23
 
27
- # Define a file target.
28
-
29
- def file(name, &block)
30
- tasks[name.to_s] = FileTask.register(name, &block)
24
+ # Run a task.
25
+ def run(name)
26
+ task_manager.call(name)
31
27
  end
32
28
 
29
+ private
30
+
31
+ #
32
+ def parse_task_dependencies(name_deps, &block)
33
+ if Hash===name_deps
34
+ name = name_deps.keys[0]
35
+ deps = name_deps.values[0]
36
+ else
37
+ name = name_deps
38
+ deps = []
39
+ end
40
+ [name, deps, block]
41
+ end
33
42
  end
34
43
 
44
+ # = TaskManager Class
35
45
  #
36
- #
37
- #
38
-
39
- class Task
46
+ class TaskManager
47
+ attr :main
48
+ attr :tasks
40
49
 
41
- def self.tasks
42
- @@tasks ||= {}
50
+ def initialize
51
+ @main = nil
52
+ @tasks = {}
43
53
  end
44
54
 
45
- def self.register(name_deps, &block)
46
- if Hash===name_deps
47
- name = name_deps.keys[0]
48
- deps = name_deps.values[0]
49
- else
50
- name = name_deps
51
- deps = []
52
- end
53
- tasks[name.to_s] = new(name, *deps, &block)
55
+ def define_main(name=nil, *depend, &block)
56
+ @main = Task.new(name, *depend, &block)
57
+ tasks[@main.name] = @main
54
58
  end
55
59
 
56
- attr :name
57
- attr :preqs
58
- attr :action
59
-
60
- #
61
-
62
- def initialize(name, *preqs, &action)
63
- @name = name.to_s
64
- @preqs = preqs
65
- @action = action
60
+ def define_task(name, *depend, &block)
61
+ task = Task.new(name, *depend, &block)
62
+ tasks[task.name] = task
66
63
  end
67
64
 
68
- def call
69
- #p plan
70
- plan.each{ |name| @@tasks[name].action_call }
71
- #action_call
65
+ def call_main
66
+ return unless @main
67
+ call(@main.name)
72
68
  end
73
69
 
74
- #
75
-
76
- def action_call
77
- @action.call if @action
70
+ # Call task.
71
+ def call(name)
72
+ plan(name).each{ |name| @tasks[name].call }
73
+ #action_call
78
74
  end
79
75
 
80
- # TODO Check for circular dependencies.
81
-
82
- def plan(list=[])
76
+ # Prepare plan, checking for circular dependencies.
77
+ def plan(name, list=[])
83
78
  if list.include?(name)
84
79
  raise "Circular dependency #{name}."
85
80
  end
86
-
87
- @preqs.each do |need|
81
+ task = @tasks[name]
82
+ task.preqs.each do |need|
88
83
  need = need.to_s
89
84
  next if list.include?(need)
90
- @@tasks[need].plan(list)
85
+ @tasks[need].plan(need, list)
91
86
  end
92
- list << name
87
+ list << task.name
93
88
  return list
94
89
  end
95
90
 
96
91
  end
97
92
 
93
+ # = Task class
98
94
  #
99
- #
100
- #
95
+ class Task
96
+
97
+ attr :name
98
+ attr :preqs
99
+ attr :action
100
+
101
+ #
102
+ def initialize(name, *preqs, &action)
103
+ @name = name.to_s
104
+ @preqs = preqs
105
+ @action = action
106
+ end
107
+
108
+ #
109
+ def call
110
+ @action.call if @action
111
+ end
101
112
 
102
- class FileTask < Task
103
113
  end
104
114
 
105
- end
115
+ end #module Ratch