tap 0.9.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (244) hide show
  1. data/History +37 -30
  2. data/MIT-LICENSE +1 -1
  3. data/README +92 -44
  4. data/bin/tap +62 -75
  5. data/cmd/console.rb +42 -0
  6. data/cmd/destroy.rb +16 -0
  7. data/cmd/generate.rb +16 -0
  8. data/cmd/run.rb +126 -0
  9. data/doc/Class Reference +362 -0
  10. data/doc/Command Reference +153 -0
  11. data/doc/Tutorial +237 -0
  12. data/lib/tap.rb +6 -45
  13. data/lib/tap/app.rb +126 -500
  14. data/lib/tap/constants.rb +2 -29
  15. data/lib/tap/env.rb +555 -250
  16. data/lib/tap/file_task.rb +60 -103
  17. data/lib/tap/generator/base.rb +109 -0
  18. data/lib/tap/generator/destroy.rb +37 -0
  19. data/lib/tap/generator/generate.rb +61 -0
  20. data/lib/tap/generator/generators/command/command_generator.rb +16 -12
  21. data/lib/tap/generator/generators/command/templates/command.erb +13 -19
  22. data/lib/tap/generator/generators/config/config_generator.rb +18 -27
  23. data/lib/tap/generator/generators/config/templates/doc.erb +12 -0
  24. data/lib/tap/generator/generators/config/templates/nodoc.erb +8 -0
  25. data/lib/tap/generator/generators/file_task/file_task_generator.rb +16 -11
  26. data/lib/tap/generator/generators/file_task/templates/file.txt +11 -2
  27. data/lib/tap/generator/generators/file_task/templates/result.yml +6 -0
  28. data/lib/tap/generator/generators/file_task/templates/task.erb +24 -31
  29. data/lib/tap/generator/generators/file_task/templates/test.erb +18 -22
  30. data/lib/tap/generator/generators/root/root_generator.rb +45 -31
  31. data/lib/tap/generator/generators/root/templates/Rakefile +64 -41
  32. data/lib/tap/generator/generators/root/templates/gemspec +27 -0
  33. data/lib/tap/generator/generators/root/templates/tapfile +8 -0
  34. data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +0 -0
  35. data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +1 -1
  36. data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +15 -0
  37. data/lib/tap/generator/generators/task/task_generator.rb +21 -28
  38. data/lib/tap/generator/generators/task/templates/task.erb +13 -23
  39. data/lib/tap/generator/generators/task/templates/test.erb +15 -18
  40. data/lib/tap/generator/manifest.rb +14 -0
  41. data/lib/tap/patches/rake/rake_test_loader.rb +0 -0
  42. data/lib/tap/patches/rake/testtask.rb +0 -0
  43. data/lib/tap/patches/ruby19/backtrace_filter.rb +0 -0
  44. data/lib/tap/patches/ruby19/parsedate.rb +0 -0
  45. data/lib/tap/root.rb +260 -21
  46. data/lib/tap/support/aggregator.rb +11 -11
  47. data/lib/tap/support/assignments.rb +172 -0
  48. data/lib/tap/support/audit.rb +20 -18
  49. data/lib/tap/support/batchable.rb +21 -10
  50. data/lib/tap/support/batchable_class.rb +107 -0
  51. data/lib/tap/support/class_configuration.rb +154 -239
  52. data/lib/tap/support/command_line.rb +97 -102
  53. data/lib/tap/support/comment.rb +270 -0
  54. data/lib/tap/support/configurable.rb +86 -65
  55. data/lib/tap/support/configurable_class.rb +296 -0
  56. data/lib/tap/support/configuration.rb +122 -0
  57. data/lib/tap/support/constant.rb +70 -0
  58. data/lib/tap/support/constant_utils.rb +127 -0
  59. data/lib/tap/support/declarations.rb +111 -0
  60. data/lib/tap/support/executable.rb +30 -17
  61. data/lib/tap/support/executable_queue.rb +0 -0
  62. data/lib/tap/support/framework.rb +71 -0
  63. data/lib/tap/support/framework_class.rb +199 -0
  64. data/lib/tap/support/instance_configuration.rb +147 -0
  65. data/lib/tap/support/lazydoc.rb +428 -0
  66. data/lib/tap/support/manifest.rb +89 -0
  67. data/lib/tap/support/run_error.rb +0 -0
  68. data/lib/tap/support/shell_utils.rb +33 -9
  69. data/lib/tap/support/summary.rb +30 -0
  70. data/lib/tap/support/tdoc.rb +339 -134
  71. data/lib/tap/support/tdoc/tdoc_html_generator.rb +0 -0
  72. data/lib/tap/support/tdoc/tdoc_html_template.rb +0 -0
  73. data/lib/tap/support/templater.rb +180 -0
  74. data/lib/tap/support/validation.rb +409 -76
  75. data/lib/tap/support/versions.rb +5 -3
  76. data/lib/tap/task.rb +78 -174
  77. data/lib/tap/tasks/dump.rb +56 -0
  78. data/lib/tap/tasks/rake.rb +93 -0
  79. data/lib/tap/test.rb +3 -3
  80. data/lib/tap/test/env_vars.rb +2 -2
  81. data/lib/tap/test/file_methods.rb +19 -20
  82. data/lib/tap/test/script_methods.rb +144 -0
  83. data/lib/tap/test/subset_methods.rb +1 -1
  84. data/lib/tap/test/tap_methods.rb +28 -62
  85. data/lib/tap/workflow.rb +22 -39
  86. metadata +48 -179
  87. data/Basic Overview +0 -151
  88. data/Command Reference +0 -99
  89. data/Rakefile +0 -127
  90. data/Tutorial +0 -287
  91. data/lib/tap/cmd/console.rb +0 -31
  92. data/lib/tap/cmd/destroy.rb +0 -20
  93. data/lib/tap/cmd/generate.rb +0 -20
  94. data/lib/tap/cmd/run.rb +0 -151
  95. data/lib/tap/dump.rb +0 -57
  96. data/lib/tap/generator.rb +0 -91
  97. data/lib/tap/generator/generators/command/USAGE +0 -6
  98. data/lib/tap/generator/generators/config/USAGE +0 -21
  99. data/lib/tap/generator/generators/config/templates/config.erb +0 -1
  100. data/lib/tap/generator/generators/file_task/USAGE +0 -3
  101. data/lib/tap/generator/generators/file_task/templates/file.yml +0 -3
  102. data/lib/tap/generator/generators/generator/USAGE +0 -0
  103. data/lib/tap/generator/generators/generator/generator_generator.rb +0 -21
  104. data/lib/tap/generator/generators/generator/templates/generator.erb +0 -32
  105. data/lib/tap/generator/generators/generator/templates/usage.erb +0 -1
  106. data/lib/tap/generator/generators/root/USAGE +0 -0
  107. data/lib/tap/generator/generators/root/templates/ReadMe.txt +0 -0
  108. data/lib/tap/generator/generators/root/templates/tap.yml +0 -80
  109. data/lib/tap/generator/generators/task/USAGE +0 -3
  110. data/lib/tap/generator/generators/workflow/USAGE +0 -0
  111. data/lib/tap/generator/generators/workflow/templates/task.erb +0 -16
  112. data/lib/tap/generator/generators/workflow/templates/test.erb +0 -7
  113. data/lib/tap/generator/generators/workflow/workflow_generator.rb +0 -6
  114. data/lib/tap/generator/options.rb +0 -26
  115. data/lib/tap/generator/usage.rb +0 -26
  116. data/lib/tap/support/batchable_methods.rb +0 -34
  117. data/lib/tap/support/command_line_methods.rb +0 -76
  118. data/lib/tap/support/configurable_methods.rb +0 -224
  119. data/lib/tap/support/logger.rb +0 -88
  120. data/lib/tap/support/rake.rb +0 -43
  121. data/lib/tap/support/tdoc/config_attr.rb +0 -362
  122. data/test/app/config/another/task.yml +0 -1
  123. data/test/app/config/batch.yml +0 -2
  124. data/test/app/config/empty.yml +0 -0
  125. data/test/app/config/erb.yml +0 -2
  126. data/test/app/config/some/task.yml +0 -1
  127. data/test/app/config/template.yml +0 -2
  128. data/test/app/config/version-0.1.yml +0 -1
  129. data/test/app/config/version.yml +0 -1
  130. data/test/app/lib/app_test_task.rb +0 -3
  131. data/test/app_test.rb +0 -1849
  132. data/test/env/test_configure/recurse_a.yml +0 -2
  133. data/test/env/test_configure/recurse_b.yml +0 -2
  134. data/test/env/test_configure/tap.yml +0 -23
  135. data/test/env/test_load_env_config/dir/tap.yml +0 -3
  136. data/test/env/test_load_env_config/recurse_a.yml +0 -2
  137. data/test/env/test_load_env_config/recurse_b.yml +0 -2
  138. data/test/env/test_load_env_config/tap.yml +0 -3
  139. data/test/env_test.rb +0 -198
  140. data/test/file_task/config/batch.yml +0 -2
  141. data/test/file_task/config/configured.yml +0 -1
  142. data/test/file_task/old_file_one.txt +0 -0
  143. data/test/file_task/old_file_two.txt +0 -0
  144. data/test/file_task_test.rb +0 -1291
  145. data/test/root/alt_lib/alt_module.rb +0 -4
  146. data/test/root/file.txt +0 -0
  147. data/test/root/glob/one.txt +0 -0
  148. data/test/root/glob/two.txt +0 -0
  149. data/test/root/lib/absolute_alt_filepath.rb +0 -2
  150. data/test/root/lib/alternative_filepath.rb +0 -2
  151. data/test/root/lib/another_module.rb +0 -2
  152. data/test/root/lib/nested/some_module.rb +0 -4
  153. data/test/root/lib/no_module_included.rb +0 -0
  154. data/test/root/lib/some/module.rb +0 -4
  155. data/test/root/lib/some_class.rb +0 -2
  156. data/test/root/lib/some_module.rb +0 -3
  157. data/test/root/load_path/load_path_module.rb +0 -2
  158. data/test/root/load_path/skip_module.rb +0 -2
  159. data/test/root/mtime/older.txt +0 -0
  160. data/test/root/unload/full_path.rb +0 -2
  161. data/test/root/unload/loaded_by_nested.rb +0 -2
  162. data/test/root/unload/nested/nested_load.rb +0 -6
  163. data/test/root/unload/nested/nested_with_ext.rb +0 -4
  164. data/test/root/unload/nested/relative_path.rb +0 -4
  165. data/test/root/unload/older.rb +0 -2
  166. data/test/root/unload/unload_base.rb +0 -9
  167. data/test/root/versions/another.yml +0 -0
  168. data/test/root/versions/file-0.1.2.yml +0 -0
  169. data/test/root/versions/file-0.1.yml +0 -0
  170. data/test/root/versions/file.yml +0 -0
  171. data/test/root_test.rb +0 -718
  172. data/test/support/aggregator_test.rb +0 -99
  173. data/test/support/audit_test.rb +0 -445
  174. data/test/support/batchable_test.rb +0 -74
  175. data/test/support/class_configuration_test.rb +0 -331
  176. data/test/support/command_line_test.rb +0 -58
  177. data/test/support/configurable/config/configured.yml +0 -2
  178. data/test/support/configurable_test.rb +0 -295
  179. data/test/support/executable_queue_test.rb +0 -103
  180. data/test/support/executable_test.rb +0 -38
  181. data/test/support/logger_test.rb +0 -31
  182. data/test/support/rake_test.rb +0 -37
  183. data/test/support/shell_utils_test.rb +0 -24
  184. data/test/support/tdoc_test.rb +0 -370
  185. data/test/support/validation_test.rb +0 -54
  186. data/test/support/versions_test.rb +0 -103
  187. data/test/tap_test_helper.rb +0 -57
  188. data/test/tap_test_suite.rb +0 -7
  189. data/test/task/config/batch.yml +0 -2
  190. data/test/task/config/batched.yml +0 -2
  191. data/test/task/config/configured.yml +0 -1
  192. data/test/task/config/example.yml +0 -1
  193. data/test/task_base_test.rb +0 -24
  194. data/test/task_syntax_test.rb +0 -300
  195. data/test/task_test.rb +0 -320
  196. data/test/test/env_vars_test.rb +0 -48
  197. data/test/test/file_methods/test_assert_files/expected/one.txt +0 -1
  198. data/test/test/file_methods/test_assert_files/expected/two.txt +0 -1
  199. data/test/test/file_methods/test_assert_files/input/one.txt +0 -1
  200. data/test/test/file_methods/test_assert_files/input/two.txt +0 -1
  201. data/test/test/file_methods/test_assert_files_can_have_no_expected_files_if_specified/input/one.txt +0 -1
  202. data/test/test/file_methods/test_assert_files_can_have_no_expected_files_if_specified/input/two.txt +0 -1
  203. data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/one.txt +0 -1
  204. data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/two.txt +0 -1
  205. data/test/test/file_methods/test_assert_files_fails_for_different_content/input/one.txt +0 -1
  206. data/test/test/file_methods/test_assert_files_fails_for_different_content/input/two.txt +0 -1
  207. data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/expected/one.txt +0 -1
  208. data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/one.txt +0 -1
  209. data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/two.txt +0 -1
  210. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/one.txt +0 -1
  211. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/two.txt +0 -1
  212. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/one.txt +0 -1
  213. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/two.txt +0 -1
  214. data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/one.txt +0 -1
  215. data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/two.txt +0 -1
  216. data/test/test/file_methods/test_method_glob/expected/file.yml +0 -0
  217. data/test/test/file_methods/test_method_glob/expected/file_1.txt +0 -0
  218. data/test/test/file_methods/test_method_glob/expected/file_2.txt +0 -0
  219. data/test/test/file_methods_doc/test_sub/expected/one.txt +0 -1
  220. data/test/test/file_methods_doc/test_sub/expected/two.txt +0 -1
  221. data/test/test/file_methods_doc/test_sub/input/one.txt +0 -1
  222. data/test/test/file_methods_doc/test_sub/input/two.txt +0 -1
  223. data/test/test/file_methods_doc_test.rb +0 -29
  224. data/test/test/file_methods_test.rb +0 -275
  225. data/test/test/subset_methods_test.rb +0 -171
  226. data/test/test/tap_methods/test_assert_files/expected/task/name/a.txt +0 -1
  227. data/test/test/tap_methods/test_assert_files/expected/task/name/b.txt +0 -1
  228. data/test/test/tap_methods/test_assert_files/input/a.txt +0 -1
  229. data/test/test/tap_methods/test_assert_files/input/b.txt +0 -1
  230. data/test/test/tap_methods_test.rb +0 -399
  231. data/test/workflow_test.rb +0 -120
  232. data/vendor/rails_generator.rb +0 -56
  233. data/vendor/rails_generator/base.rb +0 -263
  234. data/vendor/rails_generator/commands.rb +0 -581
  235. data/vendor/rails_generator/generated_attribute.rb +0 -42
  236. data/vendor/rails_generator/lookup.rb +0 -209
  237. data/vendor/rails_generator/manifest.rb +0 -53
  238. data/vendor/rails_generator/options.rb +0 -143
  239. data/vendor/rails_generator/scripts.rb +0 -83
  240. data/vendor/rails_generator/scripts/destroy.rb +0 -7
  241. data/vendor/rails_generator/scripts/generate.rb +0 -7
  242. data/vendor/rails_generator/scripts/update.rb +0 -12
  243. data/vendor/rails_generator/simple_logger.rb +0 -46
  244. data/vendor/rails_generator/spec.rb +0 -44
@@ -1,279 +1,194 @@
1
- autoload(:GetOptLong, 'getoptlong')
1
+ require 'tap/support/assignments'
2
+ require 'tap/support/instance_configuration'
3
+ require 'tap/support/configuration'
2
4
 
3
5
  module Tap
4
6
  module Support
5
- # == UNDER CONSTRUCTION
6
- #--
7
- #
8
- # ClassConfiguration holds the class configurations defined in a Tap::Task.
9
- # The configurations are stored as an array of declarations_array like:
10
- # [name, default, msg, declaration_class]. In addition, ClassConfiguration
11
- # collapse the array of declarations_array into a hash, which acts as the default
12
- # task configuration.
13
- #
14
- # Storing metadata about the configurations, such as the declaration_class,
15
- # allows the creation of more user-friendly configuration files and facilitates
16
- # incorporation into command-line applications.
17
- #
18
- # In general, users will not have to interact with ClassConfigurations directly.
19
- #
20
- # === Example
21
- #
22
- # class BaseTask < Tap::Configurable
23
- # class_configurations [:one, 1]
24
- # end
25
- #
26
- # BaseTask.configurations.hash # => {:one => 1}
27
- #
28
- # class SubTask < BaseTask
29
- # class_configurations(
30
- # [:one, 'one', "the first configuration"],
31
- # [:two, 'two', "the second configuration"])
32
- # end
33
- #
34
- # SubTask.configurations.hash # => {:one => 'one', :two => 'two'}
35
- #
36
- # Now you can see how the comments and declaring classes get used in the
37
- # configuration files. Note that configuration keys are stringified
38
- # for clarity (this is ok -- they will be symbolized when loaded by a
39
- # task).
40
- #
41
- # [BaseTask.configurations.format_yaml]
42
- # # BaseTask configuration
43
- # one: 1
44
- #
45
- # [SubTask.configurations.format_yaml]
46
- # # BaseTask configuration
47
- # one: one # the first configuration
48
- #
49
- # # SubTask configuration
50
- # two: two # the second configuration
51
- #
52
- #--
53
- # TODO -
54
- # Revisit config formatting... right now it's a bit jacked.
55
- #++
7
+
8
+ # ClassConfiguration tracks and handles the class configurations defined in a
9
+ # Configurable class.
56
10
  class ClassConfiguration
57
11
  include Enumerable
58
12
 
59
- # The class receiving the configurations
13
+ # The class receiving new configurations
60
14
  attr_reader :receiver
15
+
16
+ # Tracks the assignment of the config keys to receivers
17
+ attr_reader :assignments
61
18
 
62
- # An array of [receiver, configuration keys] arrays tracking
63
- # the order in which configurations were declared across all
64
- # receivers
65
- attr_reader :declarations_array
66
-
67
- # An array of configuration keys declared by self
68
- attr_reader :declarations
69
-
70
- # A hash of the unprocessed default values
71
- attr_reader :unprocessed_default
72
-
73
- # A hash of the processed default values
74
- attr_reader :default
75
-
76
- # A hash of the processing blocks
77
- attr_reader :process_blocks
19
+ # A map of config keys and instance methods used to set a
20
+ # config (ie the reader and writer for a config)
21
+ attr_reader :map
78
22
 
79
- # A placeholder to indicate when no value
80
- # was specified during a call to add.
81
- NO_VALUE = Object.new
82
-
83
23
  def initialize(receiver, parent=nil)
84
24
  @receiver = receiver
85
- @default = parent != nil ? parent.default.dup : {}
86
- @unprocessed_default = parent != nil ? parent.unprocessed_default.dup : {}
87
- @process_blocks = parent != nil ? parent.process_blocks.dup : {}
88
25
 
89
- # use same declarations array? freeze declarations to ensure order?
90
- # definitely falls out of order if parents are modfied after initialization
91
- @declarations_array = parent != nil ? parent.declarations_array.dup : []
92
- @declarations = []
93
- declarations_array << [receiver, @declarations]
26
+ if parent != nil
27
+ @map = parent.map.inject({}) do |hash, (key, config)|
28
+ hash[key] = config.dup
29
+ hash
30
+ end
31
+ @assignments = Assignments.new(parent.assignments)
32
+ else
33
+ @map = {}
34
+ @assignments = Assignments.new
35
+ end
36
+ end
37
+
38
+ # Initializes a Configuration using the inputs and sets it in self
39
+ # using name as a key, overriding the current config by that name,
40
+ # if it exists. Returns the new config.
41
+ def add(name, default=nil, attributes={})
42
+ self[name] = Configuration.new(name.to_sym, default, attributes)
94
43
  end
95
44
 
96
- # Returns true if the key has been declared by some receiver.
97
- # Note this is distinct from whether or not a particular config
98
- # is currently in the default hash.
99
- def declared?(key)
100
- key = key.to_sym
101
- declarations_array.each do |r,array|
102
- return true if array.include?(key)
103
- end
104
- false
45
+ # Removes the specified configuration.
46
+ def remove(key)
47
+ self[key] = nil
105
48
  end
106
49
 
107
- # Returns the class (receiver) that first added the config
108
- # indicated by key.
109
- def declaration_class(key)
50
+ # Gets the configuration specified by key. The key is symbolized.
51
+ def [](key)
52
+ map[key.to_sym]
53
+ end
54
+
55
+ # Assigns the configuration to key. A nil config unassigns the
56
+ # configuration key. The key is symbolized.
57
+ def []=(key, config)
110
58
  key = key.to_sym
111
- declarations_array.each do |r,array|
112
- return r if array.include?(key)
59
+
60
+ if config == nil
61
+ assignments.unassign(key)
62
+ map.delete(key)
63
+ else
64
+ assignments.assign(receiver, key) unless assignments.assigned?(key)
65
+ map[key] = config
113
66
  end
114
- nil
115
67
  end
116
68
 
117
- # Returns the configurations first declared by the specified receiver.
118
- def declarations_for(receiver)
119
- declarations_array.each do |r,array|
120
- return array if r == receiver
121
- end
122
- nil
69
+ # Returns true if key is a config key.
70
+ def key?(key)
71
+ map.has_key?(key)
123
72
  end
124
73
 
125
- # Adds a configuration. If specified, the value is processed
126
- # by the process_block and recorded adefault
127
- #
128
- # The existing value and process_block for the
129
- # configuration will not be overwritten unless specified. However,
130
- # if a configuration is added without specifying a value and no previous
131
- # default value exists, the default and unprocessed_default for the
132
- # configuration will be set to nil.
133
- #
134
- #--
135
- # Note -- existing blocks are NOT overwritten unless a new block is provided.
136
- # This allows overide of the default value in subclasses while preserving the
137
- # validation/processing code.
138
- def add(key, value=NO_VALUE, &process_block)
139
- key = key.to_sym
140
- value = unprocessed_default[key] if value == NO_VALUE
141
-
142
- declarations << key unless declared?(key)
143
- process_blocks[key] = process_block if block_given?
144
- unprocessed_default[key] = value
145
- default[key] = process(key, value)
146
-
147
- self
74
+ # Returns all config keys.
75
+ def keys
76
+ map.keys
148
77
  end
149
78
 
150
- def remove(key)
151
- key = key.to_sym
152
-
153
- process_blocks.delete(key)
154
- unprocessed_default.delete(key)
155
- default.delete(key)
156
-
157
- self
79
+ # Returns config keys in order.
80
+ def ordered_keys
81
+ assignments.values
158
82
  end
159
83
 
160
- def merge(another)
161
- # check for conflicts
162
- another.each do |receiver, key|
163
- dc = declaration_class(key)
164
- next if dc == nil || dc == receiver
165
-
166
- raise "configuration conflict: #{key} (#{receiver}) already declared by #{dc}"
167
- end
168
-
169
- # add the new configurations
170
- another.each do |receiver, key|
171
- # preserve the declarations for receiver
172
- unless declarations = declarations_for(receiver)
173
- declarations = []
174
- declarations_array << [receiver, declarations]
175
- end
176
- unless declarations.include?(key)
177
- declarations << key
178
- yield(key) if block_given?
179
- end
180
-
181
- add(key, another.unprocessed_default[key], &another.process_blocks[key])
84
+ # Returns all mapped configs.
85
+ def values
86
+ map.values
87
+ end
88
+
89
+ # True if map is empty.
90
+ def empty?
91
+ map.empty?
92
+ end
93
+
94
+ # Calls block once for each [receiver, key, config] in self,
95
+ # passing those elements as parameters, in the order in
96
+ # which they were assigned.
97
+ def each
98
+ assignments.each do |receiver, key|
99
+ yield(receiver, key, map[key])
182
100
  end
183
101
  end
184
-
185
- def each # :yields: receiver, key
186
- declarations_array.each do |receiver, keys|
187
- keys.each {|key| yield(receiver, key) }
102
+
103
+ # Calls block once for each [key, config] pair in self,
104
+ # passing those elements as parameters, in the order in
105
+ # which they were assigned.
106
+ def each_pair
107
+ assignments.each do |receiver, key|
108
+ yield(key, map[key])
188
109
  end
189
110
  end
190
111
 
191
- # Sends value to the process block identified by key and returns the result.
192
- # Returns value if no process block has been set for key.
193
- def process(key, value)
194
- block = process_blocks[key.to_sym]
195
- block ? block.call(value) : value
112
+ # Initializes and returns a new InstanceConfiguration set to self
113
+ # and bound to the receiver, if specified.
114
+ def instance_config(receiver=nil)
115
+ InstanceConfiguration.new(self, receiver)
196
116
  end
197
-
198
- # Nicely formats the configurations into yaml with messages and
199
- # declaration class divisions.
200
- def format_yaml
201
- lines = []
202
- declarations_array.each do |receiver, keys|
203
-
204
- # do not consider keys that have been removed
205
- keys = keys.delete_if {|key| !self.default.has_key?(key) }
206
- next if keys.empty?
207
-
208
- lines << "# #{receiver} configuration#{keys.length > 1 ? 's' : ''}"
209
-
210
- class_doc = Tap::Support::TDoc[receiver]
211
- configurations = (class_doc == nil ? [] : class_doc.configurations)
212
- keys.each do |key|
213
- tdoc_config = configurations.find {|config| config.name == key.to_s }
214
-
215
- # yaml adds a header and a final newline which should be removed:
216
- # {'key' => 'value'}.to_yaml # => "--- \nkey: value\n"
217
- # {'key' => 'value'}.to_yaml[5...-1] # => "key: value"
218
- yaml = {key.to_s => unprocessed_default[key]}.to_yaml[5...-1]
219
- message = tdoc_config ? tdoc_config.comment : ""
220
-
221
- lines << case
222
- when message == nil || message.empty?
223
- # if there is no message, simply add the yaml
224
- yaml
225
- when yaml !~ /\r?\n/ && message !~ /\r?\n/ && yaml.length < 25 && message.length < 30
226
- # shorthand ONLY if the config and message can be expressed in a single line
227
- message = message.gsub(/^#\s*/, "")
228
- "%-25s # %s" % [yaml, message]
229
- else
230
- lines << ""
231
- # comment out new lines and add the message
232
- message.split(/\n/).each do |msg|
233
- lines << "# #{msg.strip.gsub(/^#\s*/, '')}"
234
- end
235
- yaml
236
- end
237
- end
238
-
239
- # add a spacer line
240
- lines << ""
241
- end
242
117
 
243
- lines.compact.join("\n")
118
+ # Returns a hash of the (key, config.default) values in self.
119
+ def to_hash
120
+ hash = {}
121
+ each_pair {|key, config| hash[key] = config.default }
122
+ hash
244
123
  end
245
-
246
- def opt_map(long_option)
247
- raise ArgumentError.new("not a long option: #{long_option}") unless long_option =~ /^--(.*)$/
248
- long = $1
249
124
 
250
- each do |receiver, key|
251
- return key if long == key.to_s
252
- end
253
- nil
125
+ def code_comments
126
+ code_comments = []
127
+ values.each do |config|
128
+ code_comments << config.desc if config.desc.kind_of?(Comment)
129
+ end
130
+ code_comments
254
131
  end
255
-
256
- def to_opts
257
- collect do |receiver, key|
258
- # Note the receiver is used as a placeholder for desc,
259
- # to be resolved using TDoc.
260
- attributes = {
261
- :long => key,
262
- :short => nil,
263
- :opt_type => GetoptLong::REQUIRED_ARGUMENT,
264
- :desc => receiver
265
- }
266
-
267
- long = attributes[:long]
268
- attributes[:long] = "--#{long}" unless long =~ /^-{2}/
269
-
270
- short = attributes[:short].to_s
271
- attributes[:short] = "-#{short}" unless short.empty? || short =~ /^-/
132
+
133
+ # The path to the :doc template (see format_str)
134
+ DOC_TEMPLATE_PATH = File.expand_path File.dirname(__FILE__) + "/../generator/generators/config/templates/doc.erb"
135
+
136
+ # The path to the :nodoc template (see format_str)
137
+ NODOC_TEMPLATE_PATH = File.expand_path File.dirname(__FILE__) + "/../generator/generators/config/templates/nodoc.erb"
272
138
 
273
- [attributes[:long], attributes[:short], attributes[:opt_type], attributes[:desc]]
274
- end
139
+ # Formats the configurations using the specified template. Two default
140
+ # templates are defined, <tt>:doc</tt> and <tt>:nodoc</tt>. These map
141
+ # to the contents of DOC_TEMPLATE_PATH and NODOC_TEMPLATE_PATH and
142
+ # correspond to the documented and undocumented config generator templates.
143
+ #
144
+ # == Custom Templates
145
+ #
146
+ # format_str initializes a Templater which formats each [receiver, configurations]
147
+ # pair in turn, and puts the output to the target using <tt><<</tt>. The
148
+ # templater is assigned the following attributes for use in formatting:
149
+ #
150
+ # receiver:: The receiver
151
+ # class_doc:: The TDoc for the receiver, from Tap::Support::TDoc[receiver]
152
+ # configurations:: An array of configurations and associated comments
153
+ #
154
+ # In the template these can be accessed as any ERB locals, for example:
155
+ #
156
+ # <%= receiver.to_s %>
157
+ # <% configurations.each do |key, config, comment| %>
158
+ # ...
159
+ # <% end %>
160
+ #
161
+ # The input template may be a String or an ERB; either may be used to
162
+ # initialize the templater.
163
+ def format_str(template=:doc, target="")
164
+ Lazydoc.resolve(code_comments)
165
+
166
+ template = case template
167
+ when :doc then File.read(DOC_TEMPLATE_PATH)
168
+ when :nodoc then File.read(NODOC_TEMPLATE_PATH)
169
+ else template
170
+ end
171
+
172
+ templater = Templater.new(template)
173
+ assignments.each_pair do |receiver, keys|
174
+ next if keys.empty?
175
+
176
+ # set the template attributes
177
+ templater.receiver = receiver
178
+ templater.configurations = keys.collect do |key|
179
+ # duplicate config so that any changes to it
180
+ # during templation will not propogate back
181
+ # into self
182
+ [key, map[key].dup]
183
+ end.compact
184
+
185
+ yield(templater) if block_given?
186
+ target << templater.build
187
+ end
188
+
189
+ target
275
190
  end
276
-
277
191
  end
278
192
  end
279
- end
193
+ end
194
+
@@ -1,103 +1,98 @@
1
- module Tap
2
- module Support
3
-
4
- # Under Construction
5
- module CommandLine
6
- module_function
7
-
8
- # Parses the input string as YAML, if the string matches the YAML document
9
- # specifier (ie it begins with "---\s*\n"). Otherwise returns the string.
10
- #
11
- # str = {'key' => 'value'}.to_yaml # => "--- \nkey: value\n"
12
- # Tap::Script.parse_yaml(str) # => {'key' => 'value'}
13
- # Tap::Script.parse_yaml("str") # => "str"
14
- def parse_yaml(str)
15
- str =~ /\A---\s*\n/ ? YAML.load(str) : str
16
- end
17
-
18
- def split_argv(argv)
19
- current = []
20
- current_split = []
21
- splits = [current_split]
22
-
23
- argv.each do |arg|
24
- if arg =~ /\A-{2}(\+*)\z/
25
- current_split << current unless current.empty?
26
- current = []
27
- current_split = (splits[$1.length] ||= [])
28
- else
29
- current << arg
30
- end
31
- end
32
-
33
- current_split << current unless current.empty?
34
- splits.delete_if {|split| split.nil? || split.empty? }
35
- splits
36
- end
37
-
38
- def next_arg(argv)
39
- index = nil
40
- argv.each_with_index do |arg, i|
41
- if arg !~ /\A-/
42
- index = i
43
- break
44
- end
45
- end
46
- index == nil ? nil : argv.delete_at(index)
47
- end
48
-
49
- # Handles options using GetoptLong, and passes each option and
50
- # value in ARGV to the block.
51
- #
52
- #--
53
- # expect [long, <short>, type, desc]
54
- #++
55
- def handle_options(*options)
56
- options = options.collect do |opt|
57
- opt = opt[0..-2]
58
- opt.compact
59
- end
60
-
61
- opts = GetoptLong.new(*options)
62
- opts.quiet = true
63
- opts.each do |opt, value|
64
- yield(opt, value)
65
- end
66
- end
67
-
68
- def command_help(program_file, opts)
69
- lines = []
70
- lines << usage(program_file, "Usage", "Description", :keep_headers => false)
71
- unless opts.empty?
72
- lines.concat ["Options:", usage_options(opts)]
73
- end
74
- lines.join("\n")
75
- end
76
-
77
- def usage(program_file, *sections)
78
- options = sections.last.kind_of?(Hash) ? sections.pop : {}
79
- options = {:keep_headers => true}.merge(options)
80
- comment = Tap::Support::TDoc.usage(program_file, sections, options[:keep_headers])
81
- comment.rstrip + "\n"
82
- end
83
-
84
- def usage_options(opts)
85
- opt_lines = []
86
- opts.each do |long, short, mode, desc|
87
-
88
- if desc.kind_of?(Class) && desc.include?(Tap::Support::Configurable)
89
- key = desc.configurations.opt_map(long)
90
- default = PP.singleline_pp(desc.configurations.default[key], "")
91
- config_attr = desc.tdoc.find_configuration_named(key.to_s)
92
- desc = config_attr.desc
93
- end
94
-
95
- short = short == nil ? " " : "(#{short})"
96
- opt_lines << " %-25s %s %s" % [long, short, desc]
97
- end
98
- opt_lines.join("\n")
99
- end
100
-
101
- end
102
- end
1
+ require 'optparse'
2
+
3
+ module Tap
4
+ module Support
5
+
6
+ # Under Construction
7
+ module CommandLine
8
+ module_function
9
+
10
+ # Parses the input string as YAML, if the string matches the YAML document
11
+ # specifier (ie it begins with "---\s*\n"). Otherwise returns the string.
12
+ #
13
+ # str = {'key' => 'value'}.to_yaml # => "--- \nkey: value\n"
14
+ # Tap::Script.parse_yaml(str) # => {'key' => 'value'}
15
+ # Tap::Script.parse_yaml("str") # => "str"
16
+ def parse_yaml(str)
17
+ str =~ /\A---\s*\n/ ? YAML.load(str) : str
18
+ end
19
+
20
+ SPLIT_ARGV_REGEXP = /\A-{2}(\+*)\z/
21
+
22
+ def split(argv)
23
+ current = []
24
+ current_split = []
25
+ splits = [current_split]
26
+
27
+ argv.each do |arg|
28
+ if arg =~ SPLIT_ARGV_REGEXP
29
+ current_split << current unless current.empty?
30
+ current = []
31
+ current_split = (splits[$1.length] ||= [])
32
+ else
33
+ current << arg
34
+ end
35
+ end
36
+
37
+ current_split << current unless current.empty?
38
+ splits.delete_if {|split| split.nil? || split.empty? }
39
+ splits
40
+ end
41
+
42
+ def shift(argv)
43
+ index = nil
44
+ argv.each_with_index do |arg, i|
45
+ if arg !~ /\A-/
46
+ index = i
47
+ break
48
+ end
49
+ end
50
+ index == nil ? nil : argv.delete_at(index)
51
+ end
52
+
53
+ def usage(path, cols=80)
54
+ parse_usage(File.read(path), cols)
55
+ end
56
+
57
+ def parse_usage(str, cols=80)
58
+ scanner = StringScanner.new(str)
59
+ scanner.scan(/^#!.*?$/)
60
+ Comment.parse(scanner, false).wrap(cols, 2).strip
61
+ end
62
+
63
+ def configv(config)
64
+ desc = config.desc
65
+ desc.extend(OptParseComment) if desc.kind_of?(Comment)
66
+
67
+ [config.short, argtype(config), desc].compact
68
+ end
69
+
70
+ def argtype(config)
71
+ case config.arg_type
72
+ when :optional
73
+ "#{config.long} [#{config.arg_name}]"
74
+ when :switch
75
+ config.long(true)
76
+ when :flag
77
+ config.long
78
+ when :list
79
+ "#{config.long} a,b,c"
80
+ when :mandatory, nil
81
+ "#{config.long} #{config.arg_name}"
82
+ else
83
+ raise "unknown arg_type: #{config.arg_type}"
84
+ end
85
+ end
86
+
87
+ module OptParseComment
88
+ def empty?
89
+ to_str.empty?
90
+ end
91
+
92
+ def to_str
93
+ subject.to_s =~ /#(.*)$/ ? $1.strip : ""
94
+ end
95
+ end
96
+ end
97
+ end
103
98
  end