tap 0.7.9 → 0.8.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 (149) hide show
  1. data/History +28 -0
  2. data/MIT-LICENSE +1 -1
  3. data/README +71 -43
  4. data/Rakefile +81 -64
  5. data/Tutorial +235 -0
  6. data/bin/tap +80 -44
  7. data/lib/tap.rb +41 -12
  8. data/lib/tap/app.rb +243 -246
  9. data/lib/tap/file_task.rb +357 -118
  10. data/lib/tap/generator.rb +88 -29
  11. data/lib/tap/generator/generators/config/config_generator.rb +4 -2
  12. data/lib/tap/generator/generators/config/templates/config.erb +1 -2
  13. data/lib/tap/generator/generators/file_task/file_task_generator.rb +3 -18
  14. data/lib/tap/generator/generators/file_task/templates/task.erb +22 -15
  15. data/lib/tap/generator/generators/file_task/templates/test.erb +13 -2
  16. data/{test/test/inference_methods/test_assert_files_exist/input/input_1.txt → lib/tap/generator/generators/generator/USAGE} +0 -0
  17. data/lib/tap/generator/generators/generator/generator_generator.rb +21 -0
  18. data/lib/tap/generator/generators/generator/templates/generator.erb +23 -0
  19. data/lib/tap/generator/generators/generator/templates/usage.erb +1 -0
  20. data/{test/test/inference_methods/test_assert_files_exist/input/input_2.txt → lib/tap/generator/generators/package/USAGE} +0 -0
  21. data/lib/tap/generator/generators/package/package_generator.rb +38 -0
  22. data/lib/tap/generator/generators/package/templates/package.erb +186 -0
  23. data/lib/tap/generator/generators/root/root_generator.rb +14 -9
  24. data/lib/tap/generator/generators/root/templates/Rakefile +20 -14
  25. data/{test/test/inference_methods/test_infer_glob/expected/file.yml → lib/tap/generator/generators/root/templates/ReadMe.txt} +0 -0
  26. data/lib/tap/generator/generators/root/templates/tap.yml +82 -0
  27. data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +0 -1
  28. data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +2 -1
  29. data/{test/test/inference_methods/test_infer_glob/expected/file_1.txt → lib/tap/generator/generators/script/USAGE} +0 -0
  30. data/lib/tap/generator/generators/script/script_generator.rb +17 -0
  31. data/lib/tap/generator/generators/script/templates/script.erb +42 -0
  32. data/lib/tap/generator/generators/task/task_generator.rb +1 -1
  33. data/lib/tap/generator/generators/task/templates/task.erb +24 -16
  34. data/lib/tap/generator/generators/task/templates/test.erb +13 -17
  35. data/lib/tap/generator/generators/workflow/templates/task.erb +10 -10
  36. data/lib/tap/generator/generators/workflow/templates/test.erb +1 -1
  37. data/lib/tap/generator/generators/workflow/workflow_generator.rb +3 -18
  38. data/lib/tap/root.rb +108 -146
  39. data/lib/tap/script.rb +362 -0
  40. data/lib/tap/script/console.rb +28 -0
  41. data/lib/tap/script/destroy.rb +13 -1
  42. data/lib/tap/script/generate.rb +13 -1
  43. data/lib/tap/script/run.rb +100 -57
  44. data/lib/tap/support/batch_queue.rb +0 -3
  45. data/lib/tap/support/logger.rb +6 -3
  46. data/lib/tap/support/rake.rb +54 -0
  47. data/lib/tap/support/task_configuration.rb +169 -0
  48. data/lib/tap/support/tdoc.rb +198 -0
  49. data/lib/tap/support/tdoc/config_attr.rb +338 -0
  50. data/lib/tap/support/tdoc/tdoc_html_generator.rb +38 -0
  51. data/lib/tap/support/tdoc/tdoc_html_template.rb +42 -0
  52. data/lib/tap/support/versions.rb +33 -1
  53. data/lib/tap/task.rb +339 -227
  54. data/lib/tap/test.rb +86 -128
  55. data/lib/tap/test/env_vars.rb +16 -5
  56. data/lib/tap/test/file_methods.rb +373 -0
  57. data/lib/tap/test/subset_methods.rb +299 -180
  58. data/lib/tap/version.rb +2 -1
  59. data/lib/tap/workflow.rb +2 -0
  60. data/test/app/lib/app_test_task.rb +1 -0
  61. data/test/app_test.rb +327 -83
  62. data/test/check/binding_eval.rb +23 -0
  63. data/test/check/define_method_check.rb +22 -0
  64. data/test/check/dependencies_check.rb +175 -0
  65. data/test/check/inheritance_check.rb +22 -0
  66. data/test/file_task_test.rb +524 -291
  67. data/test/{test/inference_methods/test_infer_glob/expected/file_2.txt → root/glob/one.txt} +0 -0
  68. data/test/root/glob/two.txt +0 -0
  69. data/test/root_test.rb +330 -262
  70. data/test/script_test.rb +194 -0
  71. data/test/support/audit_test.rb +5 -2
  72. data/test/support/combinator_test.rb +10 -10
  73. data/test/support/rake_test.rb +35 -0
  74. data/test/support/task_configuration_test.rb +272 -0
  75. data/test/support/tdoc_test.rb +363 -0
  76. data/test/support/templater_test.rb +2 -2
  77. data/test/support/versions_test.rb +32 -0
  78. data/test/tap_test_helper.rb +39 -0
  79. data/test/task_base_test.rb +115 -0
  80. data/test/task_class_test.rb +56 -4
  81. data/test/task_execute_test.rb +29 -0
  82. data/test/task_test.rb +89 -70
  83. data/test/test/env_vars_test.rb +48 -0
  84. data/test/test/{inference_methods → file_methods}/test_assert_expected/expected/file.txt +0 -0
  85. data/test/test/{inference_methods → file_methods}/test_assert_expected/expected/folder/file.txt +0 -0
  86. data/test/test/{inference_methods → file_methods}/test_assert_expected/input/file.txt +0 -0
  87. data/test/test/{inference_methods → file_methods}/test_assert_expected/input/folder/file.txt +0 -0
  88. data/test/test/file_methods/test_assert_files_exist/input/input_1.txt +0 -0
  89. data/test/test/file_methods/test_assert_files_exist/input/input_2.txt +0 -0
  90. data/test/test/file_methods/test_assert_output_files_equal/expected/one.txt +1 -0
  91. data/test/test/file_methods/test_assert_output_files_equal/expected/two.txt +1 -0
  92. data/test/test/file_methods/test_assert_output_files_equal/input/one.txt +1 -0
  93. data/test/test/file_methods/test_assert_output_files_equal/input/two.txt +1 -0
  94. data/test/test/{inference_methods → file_methods}/test_file_compare/expected/output_1.txt +0 -0
  95. data/test/test/{inference_methods → file_methods}/test_file_compare/expected/output_2.txt +0 -0
  96. data/test/test/{inference_methods → file_methods}/test_file_compare/input/input_1.txt +0 -0
  97. data/test/test/{inference_methods → file_methods}/test_file_compare/input/input_2.txt +0 -0
  98. data/test/test/file_methods/test_infer_glob/expected/file.yml +0 -0
  99. data/test/test/file_methods/test_infer_glob/expected/file_1.txt +0 -0
  100. data/test/test/file_methods/test_infer_glob/expected/file_2.txt +0 -0
  101. data/test/test/file_methods/test_method_glob/expected/file.yml +0 -0
  102. data/test/test/file_methods/test_method_glob/expected/file_1.txt +0 -0
  103. data/test/test/file_methods/test_method_glob/expected/file_2.txt +0 -0
  104. data/test/test/{inference_methods → file_methods}/test_yml_compare/expected/output_1.yml +0 -0
  105. data/test/test/{inference_methods → file_methods}/test_yml_compare/expected/output_2.yml +0 -0
  106. data/test/test/{inference_methods → file_methods}/test_yml_compare/input/input_1.yml +0 -0
  107. data/test/test/{inference_methods → file_methods}/test_yml_compare/input/input_2.yml +0 -0
  108. data/test/test/file_methods_test.rb +204 -0
  109. data/test/test/subset_methods_test.rb +93 -33
  110. data/test/test/test_assert_expected_result_files/expected/task/name/a.txt +1 -0
  111. data/test/test/test_assert_expected_result_files/expected/task/name/b.txt +1 -0
  112. data/test/test/test_assert_expected_result_files/input/a.txt +1 -0
  113. data/test/test/test_assert_expected_result_files/input/b.txt +1 -0
  114. data/test/test/test_file_task_test/expected/one.txt +1 -0
  115. data/test/test/test_file_task_test/expected/two.txt +1 -0
  116. data/test/test/test_file_task_test/input/one.txt +1 -0
  117. data/test/test/test_file_task_test/input/two.txt +1 -0
  118. data/test/test_test.rb +143 -3
  119. data/test/workflow_test.rb +2 -0
  120. data/vendor/rails_generator.rb +56 -0
  121. data/vendor/rails_generator/base.rb +263 -0
  122. data/vendor/rails_generator/commands.rb +581 -0
  123. data/vendor/rails_generator/generated_attribute.rb +42 -0
  124. data/vendor/rails_generator/lookup.rb +209 -0
  125. data/vendor/rails_generator/manifest.rb +53 -0
  126. data/vendor/rails_generator/options.rb +143 -0
  127. data/vendor/rails_generator/scripts.rb +83 -0
  128. data/vendor/rails_generator/scripts/destroy.rb +7 -0
  129. data/vendor/rails_generator/scripts/generate.rb +7 -0
  130. data/vendor/rails_generator/scripts/update.rb +12 -0
  131. data/vendor/rails_generator/simple_logger.rb +46 -0
  132. data/vendor/rails_generator/spec.rb +44 -0
  133. metadata +180 -196
  134. data/lib/tap/generator/generators/root/templates/app.yml +0 -19
  135. data/lib/tap/generator/generators/root/templates/config/process_tap_request.yml +0 -4
  136. data/lib/tap/generator/generators/root/templates/lib/process_tap_request.rb +0 -26
  137. data/lib/tap/generator/generators/root/templates/public/images/nav.jpg +0 -0
  138. data/lib/tap/generator/generators/root/templates/public/stylesheets/color.css +0 -57
  139. data/lib/tap/generator/generators/root/templates/public/stylesheets/layout.css +0 -108
  140. data/lib/tap/generator/generators/root/templates/public/stylesheets/normalize.css +0 -40
  141. data/lib/tap/generator/generators/root/templates/public/stylesheets/typography.css +0 -21
  142. data/lib/tap/generator/generators/root/templates/server/config/environment.rb +0 -60
  143. data/lib/tap/generator/generators/root/templates/server/lib/tasks/clear_database_prerequisites.rake +0 -5
  144. data/lib/tap/generator/generators/root/templates/server/test/test_helper.rb +0 -53
  145. data/lib/tap/script/server.rb +0 -12
  146. data/lib/tap/support/rap.rb +0 -38
  147. data/lib/tap/test/inference_methods.rb +0 -298
  148. data/test/task/config/task_with_config.yml +0 -1
  149. data/test/test/inference_methods_test.rb +0 -311
@@ -1,6 +1,3 @@
1
- require 'tap/support/audit'
2
- require 'monitor'
3
-
4
1
  module Tap
5
2
  module Support
6
3
 
@@ -2,20 +2,23 @@ require 'logger'
2
2
 
3
3
  module Tap
4
4
  module Support
5
+
6
+ # == UNDER CONSTRUCTION
5
7
  # Logger provides methods to extend Logger objects.
6
8
  #
7
9
  # The output format is designed to look nice in a command prompt, but provide useful information
8
10
  # if directed at a log file. The Logger output format is like:
9
11
  #
10
- # I[datetime] type message
11
- #
12
+ # I[datetime] action message
13
+ #--
12
14
  # The first letter ('I' - INFO) indicates the severity of the message, next comes the datetime of the
13
15
  # log, the type of log message, then the message itself. Specify the log type and message like:
14
16
  #
15
17
  # logger.type "message"
16
18
  #
17
19
  # Typed logging occurs through +method_missing+. Any type is possible so long as the logger doesn't
18
- # already have a method of the input type.
20
+ # already have a method of the input type.
21
+ #++
19
22
  module Logger
20
23
  Format = " %s[%s] %18s %s\n"
21
24
 
@@ -0,0 +1,54 @@
1
+ require 'rake'
2
+
3
+ module Rake # :nodoc:
4
+ # Modifies Rake::Task to behave like a Tap::Task.
5
+ class Task # :nodoc:
6
+ alias_method(:tap_original_execute, :execute)
7
+ alias_method(:tap_original_invoke, :invoke)
8
+ alias_method(:tap_original_initialize, :initialize)
9
+
10
+ def initialize(*args)
11
+ tap_original_initialize(*args)
12
+ self.extend Tap::Task::Base
13
+ self.extend InstanceMethods
14
+ end
15
+
16
+ def invoke
17
+ @lock.synchronize do
18
+ if application.options.trace
19
+ puts "** Invoke #{name} #{format_trace_flags}"
20
+ end
21
+ return if @already_invoked
22
+ @already_invoked = true
23
+ invoke_prerequisites
24
+ tap_original_execute if needed?
25
+ end
26
+ end
27
+
28
+ module InstanceMethods # :nodoc:
29
+
30
+ def iterate=(input)
31
+ raise "iterate cannot be set to true for Rake tasks." if input == true
32
+ end
33
+
34
+ protected
35
+
36
+ def on_execute(audited_inputs)
37
+ invoke
38
+ audited_inputs._record(self, nil)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ module Tap
45
+ module Support
46
+ # == UNDER CONSTRUCTION
47
+ module Rake
48
+
49
+ def task(td, config=nil)
50
+ Object::Rake.application.lookup(td) || super
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,169 @@
1
+ module Tap
2
+ module Support
3
+ # == UNDER CONSTRUCTION
4
+ #
5
+ # TaskConfiguration holds the class configurations defined in a Tap::Task.
6
+ # The configurations are stored as an array of declarations like:
7
+ # [name, default, msg, declaration_class]. In addition, TaskConfiguration
8
+ # collapse the array of declarations into a hash, which acts as the default
9
+ # task configuration.
10
+ #
11
+ # Storing metadata about the configurations, such as the declaration_class,
12
+ # allows the creation of more user-friendly configuration files and facilitates
13
+ # incorporation into command-line applications.
14
+ #
15
+ # In general, users will not have to interact with TaskConfigurations directly.
16
+ #
17
+ # == Example
18
+ #
19
+ # class BaseTask < Tap::Task
20
+ # class_configurations [:one, 1]
21
+ # end
22
+ #
23
+ # BaseTask.configurations.hash # => {:one => 1}
24
+ #
25
+ # class SubTask < BaseTask
26
+ # class_configurations(
27
+ # [:one, 'one', "the first configuration"],
28
+ # [:two, 'two', "the second configuration"])
29
+ # end
30
+ #
31
+ # SubTask.configurations.hash # => {:one => 'one', :two => 'two'}
32
+ #
33
+ # Now you can see how the comments and declaring classes get used in the
34
+ # configuration files. Note that configuration keys are stringified
35
+ # for clarity (this is ok -- they will be symbolized when loaded by a
36
+ # task).
37
+ #
38
+ # [BaseTask.configurations.format_yaml]
39
+ # # BaseTask configuration
40
+ # one: 1
41
+ #
42
+ # [SubTask.configurations.format_yaml]
43
+ # # BaseTask configuration
44
+ # one: one # the first configuration
45
+ #
46
+ # # SubTask configuration
47
+ # two: two # the second configuration
48
+ #
49
+ class TaskConfiguration
50
+ attr_reader :declarations, :default, :attributes
51
+
52
+ include Enumerable
53
+
54
+ def initialize
55
+ @declarations = {}
56
+ @default = {}
57
+ @attributes = {}
58
+ end
59
+
60
+ def dup
61
+ # ensure the duplication does not pass along
62
+ # new references to the same objects
63
+ another = TaskConfiguration.new
64
+ another.declarations = self.declarations.dup
65
+ another.default = self.default.dup
66
+ another.attributes = self.attributes.dup
67
+ another
68
+ end
69
+
70
+ def empty?
71
+ @declaration.empty?
72
+ end
73
+
74
+ def declared?(key)
75
+ default.has_key?(key.to_sym)
76
+ end
77
+
78
+ def declare(key, declaration_class)
79
+ key = key.to_sym
80
+
81
+ # Check if the key is already declared...
82
+ return if declared?(key)
83
+
84
+ # Add a declaration array if no declaration have been
85
+ # created for the class and append the key
86
+ (declarations[declaration_class] ||= [declarations.length]) << key
87
+ default[key] = nil
88
+ attributes[key] = {}
89
+ end
90
+
91
+ def set(key, value, attributes={})
92
+ key = key.to_sym
93
+ raise "configurations cannot be set until they are declared" unless declared?(key)
94
+
95
+ default[key] = value
96
+ self.attributes[key].merge!(attributes)
97
+ end
98
+
99
+ def each # :yields: declaration_class, key, default, attributes
100
+ declarations.each_pair do |declaration_class, keys|
101
+ keys[1..-1].each do |key|
102
+ yield(declaration_class, key, default[key], attributes[key])
103
+ end
104
+ end
105
+ end
106
+
107
+ # Nicely formats the configurations into yaml with messages and
108
+ # declaration class divisions.
109
+ def format_yaml
110
+ lines = []
111
+ declarations.each_pair do |declaration_class, keys|
112
+ lines << "# #{declaration_class} configuration#{keys.length > 2 ? 's' : ''}"
113
+
114
+ class_name = declaration_class.to_s
115
+ class_path = class_name.underscore
116
+ source_file = Dependencies.search_for_file(class_path)
117
+
118
+ Tap::Support::TDoc.document(source_file)
119
+ class_doc = Tap::Support::TDoc[declaration_class]
120
+ configurations = (class_doc == nil ? [] : class_doc.configurations)
121
+
122
+ keys[1..-1].each do |key|
123
+ value = default[key]
124
+ attribs = attributes[key]
125
+ message = ""
126
+ configurations.each do |config|
127
+ if config.name == key.to_s
128
+ message = config.comment
129
+ break
130
+ end
131
+ end
132
+
133
+ # yaml adds a header and a final newline which should be removed:
134
+ # {'key' => 'value'}.to_yaml # => "--- \nkey: value\n"
135
+ # {'key' => 'value'}.to_yaml[5...-1] # => "key: value"
136
+ yaml = {key.to_s => value}.to_yaml[5...-1]
137
+ #yaml = "##{yaml}" if value.nil?
138
+
139
+ lines << case
140
+ when message == nil || message.empty?
141
+ # if there is no message, simply add the yaml
142
+ yaml
143
+ when yaml !~ /\r?\n/ && message !~ /\r?\n/ && yaml.length < 20 && message.length < 30
144
+ # shorthand ONLY if the config and message can be expressed in a single line
145
+ message = message.gsub(/^#\s*/, "")
146
+ "%-20s # %s" % [yaml, message]
147
+ else
148
+ # comment out new lines and add the message
149
+ message = message.gsub(/\n#\s*/, "\n# ")
150
+ lines << "# #{message}"
151
+ yaml
152
+ end
153
+ end
154
+
155
+ # add a spacer line
156
+ lines << ""
157
+ end
158
+
159
+ lines.join("\n")
160
+ end
161
+
162
+
163
+ protected
164
+
165
+ attr_writer :declarations, :default, :attributes
166
+
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,198 @@
1
+ require 'tap/support/tdoc/config_attr'
2
+ require 'singleton'
3
+
4
+ module Tap
5
+ module Support
6
+
7
+ # == Overview
8
+ # TDoc hooks into and extends RDoc to make task documentation available for command line
9
+ # applications as well as for inclusion in RDoc html. In particular, TDoc makes available
10
+ # documentation for Task configurations, when they are present. TDoc provides an extension
11
+ # to the standard RDoc HTMLGenerator and template.
12
+ #
13
+ # == Usage
14
+ # To generate task documentation with configuration information, TDoc must be loaded and
15
+ # the appropriate flags passed to rdoc . Essentially what you want is:
16
+ #
17
+ # % rdoc --fmt tdoc --template tap/support/tdoc/tdoc_html_template [file_names....]
18
+ #
19
+ # Unfortunately, there is no way to load or require a file into the rdoc utility directly; the
20
+ # above code causes an 'Invalid output formatter' error. However, TDoc is easy to utilize
21
+ # from a Rake::RDocTask:
22
+ #
23
+ # require 'rake'
24
+ # require 'rake/rdoctask'
25
+ #
26
+ # desc 'Generate documentation.'
27
+ # Rake::RDocTask.new(:rdoc) do |rdoc|
28
+ # require 'tap/support/tdoc'
29
+ # rdoc.template = 'tap/support/tdoc/tdoc_html_template'
30
+ # rdoc.options << '--fmt' << 'tdoc'
31
+ #
32
+ # # specify whatever else you need
33
+ # # rdoc.rdoc_files.include(...)
34
+ # end
35
+ #
36
+ # Now execute the rake task like:
37
+ #
38
+ # % rake rdoc
39
+ #
40
+ # TDoc may also be utilized programatically, but you should be aware that RDoc in Ruby
41
+ # can raise errors and/or cause namespace conflicts (see below).
42
+ #
43
+ # == Implementation
44
+ # RDoc is a beast to utilize in a non-standard way. One way to make RDoc parse unexpected
45
+ # flags like 'config_accessor' or the 'c' config specifier is to use the '--accessor' option
46
+ # (see 'rdoc --help' or the RDoc documentation for more details).
47
+ #
48
+ # TDoc hooks into the '--accessor' parsing process to pull out configuration attributes and
49
+ # format them into their own Configuration section on an RDoc html page. When 'tdoc' is
50
+ # specified as an rdoc option, TDoc in effect sets accessor flags for all the standard Task
51
+ # configuration methods, and then extends the RDoc::RubyParser handle these specially.
52
+ #
53
+ # If 'tdoc' is not specified as the rdoc format, TDoc does not affect the RDoc output.
54
+ # Similarly, the configuration attributes will not appear in the output unless you specify a
55
+ # template that utilizes them.
56
+ #
57
+ # == Namespace conflicts
58
+ # RDoc creates a namespace conflict with other libraries that define RubyToken and RubyLex
59
+ # in the Object namespace (the prime example being IRB). TDoc checks for such a conflict
60
+ # and redfines the RDoc RubyToken and RubyLex within the RDoc namespace. Essentially:
61
+ #
62
+ # RubyToken => RDoc::RubyToken
63
+ # RubyLex => RDoc::RubyLex
64
+ #
65
+ # The redefinition should not affect the existing RubyToken and RubyLex constants, but if
66
+ # you directly use the RDoc versions after loading TDoc, you should be aware that they must
67
+ # be accessed through the new constants. Unfortunatley the trick is not seamless. The RDoc
68
+ # RubyLex makes a few calls to the RubyLex class method 'debug?'... these will be issued to
69
+ # the existing RubyLex method and not RDoc::RubyLex.debug?
70
+ #
71
+ # In addition, because of the RubyLex calls, the RDoc::RubyLex cannot be fully hidden when
72
+ # TDoc is loaded before the conflicting RubyLex; you cannot load TDoc before loading IRB
73
+ # without raising warnings. I hope to submit a patch for RDoc to stop this nonsense in the
74
+ # future.
75
+ #
76
+ # On the plus side, you can now access/use RDoc within irb by requiring 'tap/support/tdoc'.
77
+ #
78
+ class TDoc
79
+ include Singleton
80
+
81
+ attr_accessor :stats, :options, :documented_files, :load_paths
82
+
83
+ def initialize
84
+ reinitialize
85
+ end
86
+
87
+ def reinitialize(argv=['--fmt', 'tdoc', '--quiet'])
88
+ @documented_files = []
89
+ @tl = RDoc::TopLevel::reset
90
+ @stats = RDoc::Stats.new
91
+ @options = Options.instance
92
+ @options.parse(argv, RDoc::RDoc::GENERATORS)
93
+ @load_paths = $:
94
+ end
95
+
96
+ class << self
97
+
98
+ def search_for_files(path_suffix)
99
+ # modified from 'activesupport/dependencies'
100
+ path_suffix = path_suffix + '.rb' unless path_suffix.ends_with? '.rb'
101
+
102
+ files = instance.load_paths.collect do |root|
103
+ path = File.join(root, path_suffix)
104
+ File.file?(path) ? path : nil
105
+ end.compact
106
+ end
107
+
108
+ def search_for_source_files(klass)
109
+ source_files = search_for_files(klass.to_s.underscore)
110
+ while klass.superclass.kind_of?(Tap::Task)
111
+ klass = klass.superclass
112
+ break if klass.configurations.empty?
113
+ source_files.concat(search_for_files(klass.to_s.underscore))
114
+ end
115
+
116
+ source_files.uniq
117
+ end
118
+
119
+ def document(*filepaths)
120
+ filepaths.each do |filepath|
121
+ next if filepath == nil || instance.documented_files.include?(filepath) || !File.exists?(filepath)
122
+
123
+ tl = RDoc::TopLevel.new(filepath)
124
+ parser = RDoc::RubyParser.new(tl, filepath, File.read(filepath), instance.options, instance.stats)
125
+ parser.scan
126
+ instance.documented_files << filepath
127
+ end
128
+ end
129
+
130
+ def find_class_or_module_named(name)
131
+ RDoc::TopLevel.all_classes_and_modules.each do |c|
132
+ res = c.find_class_or_module_named(name)
133
+ return res if res
134
+ end
135
+ nil
136
+ end
137
+
138
+ def [](klass)
139
+ name = klass.to_s
140
+ res = find_class_or_module_named(name)
141
+
142
+ # If no result was found, try to document a sourcefile
143
+ # from the standard filepath and search again
144
+ if res == nil
145
+ source_files = klass.respond_to?(:source_files) ? klass.source_files : []
146
+ source_files = search_for_source_files(klass) if source_files.empty?
147
+
148
+ unless source_files.empty?
149
+ document(*source_files)
150
+ res = find_class_or_module_named(name)
151
+ end
152
+ end
153
+
154
+ res
155
+ end
156
+
157
+ def usage(program_file, sections=[], keep_section_headers=false)
158
+ comment = []
159
+ File.open(program_file) do |file|
160
+ while line = file.gets
161
+ case line
162
+ when /^\s*$/
163
+ # skip leading blank lines
164
+ comment.empty? ? next : break
165
+ when /^\s*# ?(.*)/m
166
+ comment << $1
167
+ end
168
+ end
169
+ end
170
+
171
+ unless sections.empty?
172
+ sections_hash = {}
173
+ current_section = nil
174
+ comment.each do |line|
175
+ case line
176
+ when /^s*=+(.*)/
177
+ current_section = []
178
+ current_section << line if keep_section_headers
179
+ sections_hash[$1.strip] = current_section
180
+ else
181
+ current_section << line unless current_section.nil?
182
+ end
183
+ end
184
+
185
+ comment = []
186
+ sections.each do |section|
187
+ next unless sections_hash.has_key?(section)
188
+ comment.concat(sections_hash[section])
189
+ end
190
+ end
191
+
192
+ comment.join('')
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
198
+