ratch 0.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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