detroit 0.3.0 → 0.4.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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.index +59 -0
  3. data/EXAMPLE.md +66 -64
  4. data/{HISTORY.rdoc → HISTORY.md} +32 -5
  5. data/{COPYING.rdoc → LICENSE.txt} +0 -0
  6. data/README.md +142 -0
  7. data/bin/detroit +1 -1
  8. data/lib/detroit.rb +112 -40
  9. data/lib/detroit.yml +44 -29
  10. data/lib/detroit/assembly.rb +49 -193
  11. data/lib/detroit/basic_tool.rb +200 -0
  12. data/lib/detroit/basic_utils.rb +66 -0
  13. data/lib/detroit/core_ext.rb +2 -136
  14. data/lib/detroit/{tool/core_ext → core_ext}/facets.rb +3 -0
  15. data/lib/detroit/{tool/core_ext → core_ext}/filetest.rb +0 -0
  16. data/lib/detroit/{tool/core_ext → core_ext}/shell_extensions.rb +0 -0
  17. data/lib/detroit/{tool/core_ext → core_ext}/to_actual_filename.rb +0 -0
  18. data/lib/detroit/{tool/core_ext → core_ext}/to_console.rb +1 -0
  19. data/lib/detroit/{tool/core_ext → core_ext}/to_list.rb +0 -0
  20. data/lib/detroit/{tool/core_ext → core_ext}/to_yamlfrag.rb +0 -0
  21. data/lib/detroit/{tool/core_ext → core_ext}/unfold_paragraphs.rb +0 -0
  22. data/lib/detroit/{tool/email_utils.rb → email_utils.rb} +3 -1
  23. data/lib/detroit/exec.rb +55 -0
  24. data/lib/detroit/project.rb +134 -0
  25. data/lib/detroit/ruby_utils.rb +29 -0
  26. data/lib/detroit/{tool/shell_utils.rb → shell_utils.rb} +10 -5
  27. data/lib/detroit/toolchain.rb +6 -0
  28. data/lib/detroit/toolchain/cli.rb +320 -0
  29. data/lib/detroit/toolchain/config.rb +223 -0
  30. data/lib/detroit/toolchain/runner.rb +678 -0
  31. data/lib/detroit/toolchain/script.rb +248 -0
  32. data/lib/detroit/toolchain/worker.rb +84 -0
  33. data/man/detroit.1 +116 -0
  34. data/man/detroit.1.html +171 -0
  35. data/man/detroit.1.ronn +99 -0
  36. metadata +90 -51
  37. data/.ruby +0 -44
  38. data/README.rdoc +0 -132
  39. data/lib/detroit/application.rb +0 -463
  40. data/lib/detroit/assembly_system.rb +0 -80
  41. data/lib/detroit/config.rb +0 -203
  42. data/lib/detroit/control.rb +0 -129
  43. data/lib/detroit/custom.rb +0 -102
  44. data/lib/detroit/dsl.rb +0 -55
  45. data/lib/detroit/service.rb +0 -78
  46. data/lib/detroit/standard_assembly.rb +0 -51
  47. data/lib/detroit/tool.rb +0 -295
  48. data/lib/detroit/tool/core_ext.rb +0 -3
  49. data/lib/detroit/tool/project_utils.rb +0 -41
@@ -0,0 +1,200 @@
1
+ module Detroit
2
+
3
+ ##
4
+ # This base class can be used for tools that do not need
5
+ # all of the utility methods provided by the regular Tool
6
+ # class.
7
+ #
8
+ class BasicTool
9
+ include BasicUtils
10
+
11
+ # Call this method to register a tool with an assembly.
12
+ # A tool can only belong to one assembly, but migration
13
+ # adapters can be defined to allow tools from one assembly
14
+ # to work with another (COMING SOON).
15
+ #
16
+ # @param [Assembly] a (optional)
17
+ # Assembly for which this tool is designed.
18
+ #
19
+ # @example
20
+ # class SomeTool < Tool
21
+ # assembly Standard
22
+ #
23
+ # @return [Assembly] Assembly module.
24
+ def self.assembly(a=nil)
25
+ #include(@assembly = a) if a
26
+ include(a) if a
27
+ @assembly
28
+ end
29
+
30
+ #
31
+ def self.assembly=(a)
32
+ @assembly = a
33
+ end
34
+
35
+ ## Specify a supported station. This is used by the `chain?` method to
36
+ ## determine if station is supporte by a tool. This is more convenient
37
+ ## then overridding `chain?` method.
38
+ #def self.station(name, alt=nil)
39
+ # define_method("station_#{name}") do |options={}|
40
+ # meth = method(alt || name)
41
+ # case meth.arity
42
+ # when 0
43
+ # meth.call()
44
+ # else
45
+ # meth.call(options)
46
+ # end
47
+ # end
48
+ #end
49
+
50
+ # Returns a Class which is a new subclass of the current class.
51
+ #def self.factory(&block)
52
+ # Class.new(self, &block)
53
+ #end
54
+
55
+ # Override the usual new method in order to apply prerequisites.
56
+ #
57
+ # @return [BasicTool]
58
+ def self.new(options={})
59
+ tool = allocate
60
+ # TODO: I don't exactly like this, but how else to get project
61
+ # into the tool befire running `#prerequiste`?
62
+ tool.project = options['project']
63
+ ancestors.reverse_each do |anc|
64
+ next if (anc == BasicObject || anc == Object || anc == Kernel)
65
+ if anc.instance_methods.include?(:prerequisite)
66
+ pre = anc.instance_method(:prerequisite)
67
+ pre.bind(tool).call
68
+ end
69
+ end
70
+ tool.send(:initialize, options)
71
+ tool
72
+ end
73
+
74
+ # Returns list of writer method names. This is used for reference.
75
+ #
76
+ # @return [Array<String>]
77
+ def self.options(tool_class=self)
78
+ i = tool_class.ancestors.index(Tool)
79
+ m = []
80
+ tool_class.ancestors[0..i].each do |sc|
81
+ sc.public_instance_methods(false).each do |pm|
82
+ next if pm !~ /\w+=$/
83
+ next if %w{taguri=}.include?(m.to_s)
84
+ m << pm.to_s.chomp('=')
85
+ end
86
+ end
87
+ m
88
+ end
89
+
90
+ # Override this method if the tool's availability is conditional.
91
+ #
92
+ # @return [Boolean]
93
+ def self.available?
94
+ true
95
+ end
96
+
97
+ # This pre-initialization procedure is run before #initialize and
98
+ # for all ancestors, so `#super` should never be called within it.
99
+ # The method is intended to be used to require dependencies for a tool,
100
+ # so that tool's dependencies are only required when needed. But it can
101
+ # also be used to set pre-option attribute defaults.
102
+ #
103
+ # @example
104
+ # def prerequisite
105
+ # require 'ostruct'
106
+ # @gravy = true
107
+ # end
108
+ #
109
+ # @return [void]
110
+ def prerequisite
111
+ end
112
+
113
+ # Create a new tool object.
114
+ #
115
+ # This sets up utility extensions and assigns options to setter attributes
116
+ # if they exist and values are not nil. That last point is important.
117
+ # You must use 'false' to purposely negate an option, as +nil+ will instead
118
+ # allow any default setting to be used.
119
+ #
120
+ # @return [void]
121
+ def initialize(options={})
122
+ initialize_options(@options = options)
123
+ end
124
+
125
+ # Called by `#initialize` to call writers from given options.
126
+ #
127
+ # @return [void]
128
+ def initialize_options(options)
129
+ options.each do |k, v|
130
+ #send("#{k}=", v) unless v.nil? #if respond_to?("#{k}=") && !v.nil?
131
+ if respond_to?("#{k}=")
132
+ send("#{k}=", v) unless v.nil? #if respond_to?("#{k}=") && !v.nil?
133
+ else
134
+ warn "#{self.class.name} does not respond to `#{k}=`."
135
+ end
136
+ end
137
+ end
138
+
139
+ # Access to all options passed into `#initialize`.
140
+ #
141
+ # @return [Hash]
142
+ attr :options
143
+
144
+ #
145
+ # @todo Is this needed?
146
+ #
147
+ def title
148
+ self.class.name
149
+ end
150
+
151
+ # Does this tool attach to the specified station?
152
+ #
153
+ # By default this checks for the definition of a public method in the tool
154
+ # class with the same name as the station. Note, it does not use `respond_to?`
155
+ # to do this, which would find any such method in the class hierarchy. Instead
156
+ # it specifically checks for a definition in the tool class itself. This
157
+ # helps prevent potential accidental name clashes between support methods
158
+ # and station names.
159
+ #
160
+ def assemble?(station, options={})
161
+ self.class.public_methods(false).include?(station.to_sym)
162
+ end
163
+
164
+ #
165
+ def assemble(station, options={})
166
+ meth = method(station)
167
+
168
+ case meth.arity
169
+ when 0
170
+ meth.call()
171
+ else
172
+ meth.call(options)
173
+ end
174
+ end
175
+
176
+ # Project instance.
177
+ def project=(project)
178
+ @project = project
179
+ end
180
+
181
+ # Project instance.
182
+ def project
183
+ @project #||= Project.factory(root)
184
+ end
185
+
186
+ # Shortcut to project metadata.
187
+ def metadata
188
+ project.metadata
189
+ end
190
+
191
+ # Project root directory.
192
+ #
193
+ # @return [Pathname]
194
+ def root
195
+ @project.root
196
+ end
197
+
198
+ end
199
+
200
+ end
@@ -0,0 +1,66 @@
1
+ module Detroit
2
+
3
+ ##
4
+ # Common utility methods included in all tools.
5
+ #
6
+ module BasicUtils
7
+
8
+ # Glob for finding root of a project.
9
+ def root_pattern
10
+ "{.index,.git,.hg,.svn,_darcs}"
11
+ end
12
+
13
+ # Project root directory.
14
+ def root
15
+ @root ||= (
16
+ path = nil
17
+ home = File.expand_path('~')
18
+
19
+ while dir != home && dir != '/'
20
+ if Dir[root_pattern].first
21
+ path = dir
22
+ break
23
+ end
24
+ dir = File.dirname(dir)
25
+ end
26
+
27
+ Pathname.new(path || Dir.pwd)
28
+ )
29
+ end
30
+
31
+ # Configuration.
32
+ def config
33
+ @config ||= Config.new(root)
34
+ end
35
+
36
+ #
37
+ def naming_policy
38
+ @naming_policy ||= (
39
+ if config.naming_policy
40
+ Array(config.naming_policy)
41
+ else
42
+ ['down', 'ext']
43
+ end
44
+ )
45
+ end
46
+
47
+ #
48
+ def apply_naming_policy(name, ext)
49
+ naming_policy.each do |policy|
50
+ case policy.to_s
51
+ when /^low/, /^down/
52
+ name = name.downcase
53
+ when /^up/
54
+ name = name.upcase
55
+ when /^cap/
56
+ name = name.capitalize
57
+ when /^ext/
58
+ name = name + ".#{ext}"
59
+ end
60
+ end
61
+ name
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -1,137 +1,3 @@
1
- #__DIR__ = File.dirname(__FILE__)
2
-
3
- #Dir[File.join(__DIR__, 'core_ext', '*.rb')].each do |file|
4
- # require file
5
- #end
6
-
7
- #require 'facets'
8
- require 'facets/to_hash'
9
- require 'facets/module/basename'
10
- require 'facets/module/alias_accessor'
11
- require 'facets/pathname'
12
- #require 'facets/boolean'
13
-
14
- class Array
15
-
16
- def to_list
17
- self
18
- end
19
-
1
+ Dir[File.dirname(__FILE__) + '/core_ext/**/*.rb'].each do |file|
2
+ require file
20
3
  end
21
-
22
- class NilClass
23
-
24
- def to_list
25
- []
26
- end
27
-
28
- end
29
-
30
- class String
31
-
32
- # Helper method for cleaning list options.
33
- # This will split the option on ':' or ';'
34
- # if it is a string, rather than an array.
35
- # And it will make sure there are no nil elements.
36
-
37
- def to_list
38
- split(/[:;,\n]/).map{ |s| s.strip }
39
- end
40
-
41
- end
42
-
43
- # TODO: Replace these with facets/shellwords !!!
44
-
45
- #
46
- class Array #:nodoc:
47
-
48
- # Convert an array into commandline parameters.
49
- # The array is accepted in the format of Ruby
50
- # method arguments --ie. [arg1, arg2, ..., hash]
51
-
52
- def to_console
53
- #flags = (Hash===last ? pop : {})
54
- #flags = flags.to_console
55
- #flags + ' ' + join(" ")
56
- to_argv.join(' ')
57
- end
58
-
59
- # TODO: DEPRECATE
60
- alias_method :to_params, :to_console
61
-
62
- #
63
- def to_argv
64
- flags = (Hash===last ? pop : {})
65
- flags = flags.to_argv
66
- flags + self
67
- end
68
-
69
- # def to_console
70
- # flags = (Hash===last ? pop : {})
71
- # flags = flags.collect do |f,v|
72
- # m = f.to_s.size == 1 ? '-' : '--'
73
- # case v
74
- # when Array
75
- # v.collect{ |e| "#{m}#{f} '#{e}'" }.join(' ')
76
- # when true
77
- # "#{m}#{f}"
78
- # when false, nil
79
- # ''
80
- # else
81
- # "#{m}#{f} '#{v}'"
82
- # end
83
- # end
84
- # return (flags + self).join(" ")
85
- # end
86
-
87
- end
88
-
89
- class Hash
90
-
91
- # Convert a Hash into command line arguments.
92
- # The array is accepted in the format of Ruby
93
- # method arguments --ie. [arg1, arg2, ..., hash]
94
- def to_console
95
- to_argv.join(' ')
96
- end
97
-
98
- # Convert a Hash into command line parameters.
99
- # The array is accepted in the format of Ruby
100
- # method arguments --ie. [arg1, arg2, ..., hash]
101
- def to_argv
102
- flags = map do |f,v|
103
- m = f.to_s.size == 1 ? '-' : '--'
104
- case v
105
- when Array
106
- v.collect{ |e| "#{m}#{f}='#{e}'" }.join(' ')
107
- when true
108
- "#{m}#{f}"
109
- when false, nil
110
- ''
111
- else
112
- "#{m}#{f}='#{v}'"
113
- end
114
- end
115
- end
116
-
117
- # Turn a hash into arguments.
118
- #
119
- # h = { :list => [1,2], :base => "HI" }
120
- # h.argumentize #=> [ [], { :list => [1,2], :base => "HI" } ]
121
- # h.argumentize(:list) #=> [ [1,2], { :base => "HI" } ]
122
- #
123
- def argumentize(args_field=nil)
124
- config = dup
125
- if args_field
126
- args = [config.delete(args_field)].flatten.compact
127
- else
128
- args = []
129
- end
130
- args << config
131
- return args
132
- end
133
-
134
- alias_method :command_vector, :argumentize
135
-
136
- end
137
-
@@ -2,6 +2,9 @@
2
2
  # see it as a "heavy" dependency. But really that is far from true, consider
3
3
  # the facet that the following libs are all that it used.
4
4
 
5
+ require 'facets/pathname'
6
+ #require 'facets/boolean'
7
+
5
8
  require 'facets/array/not_empty'
6
9
  require 'facets/module/basename'
7
10
  require 'facets/module/alias_accessor'
@@ -1,4 +1,5 @@
1
1
  # TODO: Improve the naming scheme of these methods.
2
+ # TODO: Replace these with facets/shellwords ?
2
3
 
3
4
  #
4
5
  class Array #:nodoc:
@@ -1,6 +1,8 @@
1
1
  module Detroit
2
2
 
3
- # The Mail utility module provides an easy to use +email+ method.
3
+ ##
4
+ # The Mail utility module provides an easy to use `email` method.
5
+ #
4
6
  module EmailUtils
5
7
 
6
8
  # Email function to easily send out an email.
@@ -0,0 +1,55 @@
1
+ module Detroit
2
+
3
+ # Execute a sepcific detroit tool.
4
+ #
5
+ # Note this uses the executable gem to automatically
6
+ # "cli-ify" a tool class.
7
+ #
8
+ def self.tool_exec(*argv)
9
+ require 'executable'
10
+
11
+ tool, stop = argv.shift.split(':')
12
+
13
+ raise "No tool specified." unless tool
14
+ raise "No tool stop specified." unless stop
15
+
16
+ begin
17
+ require "detroit-#{tool}"
18
+ rescue LoadError
19
+ raise "Unknown tool. Perhaps try `gem install detroit-#{tool}`."
20
+ end
21
+
22
+ tool_class = Detroit.tools[tool]
23
+
24
+ exec_class = Class.new(tool_class) do
25
+ include Executable
26
+
27
+ # TODO: Fix executable, to at least super if defined super.
28
+ define_method(:initialize) do
29
+ tool_class.instance_method(:initialize).bind(self).call
30
+ end
31
+
32
+ # Show this message.
33
+ def help!
34
+ cli.show_help
35
+ exit
36
+ end
37
+ alias :h! :help!
38
+
39
+ define_method(:call) do |*args|
40
+ if assemble?(stop.to_sym)
41
+ assemble(stop.to_sym)
42
+ else
43
+ raise "#{tool} does not know how to #{stop}."
44
+ end
45
+ end
46
+ end
47
+
48
+ #exec_class.send(:define_method, :command_name) do
49
+ # tool
50
+ #end
51
+
52
+ exec_class.run(argv)
53
+ end
54
+
55
+ end