tap 0.7.9 → 0.8.0

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