daemon-kit 0.1.7.12 → 0.1.8pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/History.txt +7 -0
  2. data/Manifest.txt +4 -0
  3. data/README.rdoc +11 -9
  4. data/Rakefile +0 -1
  5. data/TODO.txt +1 -2
  6. data/bin/daemon-kit +11 -11
  7. data/daemon-kit.gemspec +109 -78
  8. data/lib/daemon_kit.rb +7 -10
  9. data/lib/daemon_kit/abstract_logger.rb +22 -14
  10. data/lib/daemon_kit/application.rb +0 -1
  11. data/lib/daemon_kit/arguments.rb +1 -6
  12. data/lib/daemon_kit/commands/destroy.rb +10 -0
  13. data/lib/daemon_kit/commands/generate.rb +10 -0
  14. data/lib/daemon_kit/config.rb +7 -2
  15. data/lib/daemon_kit/generators.rb +67 -0
  16. data/lib/daemon_kit/generators/base.rb +60 -0
  17. data/lib/daemon_kit/initializer.rb +1 -1
  18. data/lib/daemon_kit/jabber.rb +1 -0
  19. data/lib/daemon_kit/tasks/framework.rake +6 -1
  20. data/lib/daemon_kit/vendor/thor-0.12.3/CHANGELOG.rdoc +80 -0
  21. data/lib/daemon_kit/vendor/thor-0.12.3/LICENSE +20 -0
  22. data/lib/daemon_kit/vendor/thor-0.12.3/README.rdoc +234 -0
  23. data/lib/daemon_kit/vendor/thor-0.12.3/Thorfile +64 -0
  24. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor.rb +242 -0
  25. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/actions.rb +274 -0
  26. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/actions/create_file.rb +103 -0
  27. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/actions/directory.rb +91 -0
  28. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/actions/empty_directory.rb +134 -0
  29. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/actions/file_manipulation.rb +223 -0
  30. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/actions/inject_into_file.rb +101 -0
  31. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/base.rb +515 -0
  32. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/core_ext/file_binary_read.rb +9 -0
  33. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  34. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/core_ext/ordered_hash.rb +100 -0
  35. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/error.rb +27 -0
  36. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/group.rb +271 -0
  37. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/invocation.rb +178 -0
  38. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/parser.rb +4 -0
  39. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/parser/argument.rb +67 -0
  40. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/parser/arguments.rb +145 -0
  41. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/parser/option.rb +132 -0
  42. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/parser/options.rb +142 -0
  43. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/rake_compat.rb +66 -0
  44. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/runner.rb +303 -0
  45. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/shell.rb +78 -0
  46. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/shell/basic.rb +239 -0
  47. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/shell/color.rb +108 -0
  48. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/task.rb +111 -0
  49. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/util.rb +233 -0
  50. data/lib/daemon_kit/vendor/thor-0.12.3/lib/thor/version.rb +3 -0
  51. data/lib/daemon_kit/xmpp.rb +75 -6
  52. data/{daemon_generators → lib/generators/daemon_kit}/amqp/USAGE +0 -0
  53. data/lib/generators/daemon_kit/amqp/amqp_generator.rb +24 -0
  54. data/{daemon_generators → lib/generators/daemon_kit}/amqp/templates/config/amqp.yml +0 -0
  55. data/{daemon_generators/amqp/templates/config/initializers → lib/generators/daemon_kit/amqp/templates/config/pre-daemonize}/amqp.rb +0 -0
  56. data/{daemon_generators/amqp/templates/libexec/daemon.rb → lib/generators/daemon_kit/amqp/templates/libexec/%app_name%-daemon.rb} +0 -0
  57. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/USAGE +0 -0
  58. data/lib/generators/daemon_kit/app/app_generator.rb +140 -0
  59. data/lib/generators/daemon_kit/app/templates/Gemfile +8 -0
  60. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/templates/README +0 -0
  61. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/templates/Rakefile +0 -0
  62. data/lib/generators/daemon_kit/app/templates/bin/daemon.tt +7 -0
  63. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/templates/config/arguments.rb +0 -0
  64. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/templates/config/boot.rb +10 -3
  65. data/{app_generators/daemon_kit/templates/config/environment.rb → lib/generators/daemon_kit/app/templates/config/environment.rb.tt} +1 -1
  66. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/templates/config/environments/development.rb +0 -0
  67. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/templates/config/environments/production.rb +0 -0
  68. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/templates/config/environments/test.rb +0 -0
  69. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/templates/config/post-daemonize/readme +0 -0
  70. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/templates/config/pre-daemonize/readme +0 -0
  71. data/{app_generators/daemon_kit/templates/lib/daemon.rb → lib/generators/daemon_kit/app/templates/lib/%app_name%.rb} +0 -0
  72. data/{app_generators/daemon_kit/templates/libexec/daemon.erb → lib/generators/daemon_kit/app/templates/libexec/%app_name%-daemon.rb} +0 -0
  73. data/{app_generators/daemon_kit → lib/generators/daemon_kit/app}/templates/script/console +0 -0
  74. data/lib/generators/daemon_kit/app/templates/script/destroy +2 -0
  75. data/lib/generators/daemon_kit/app/templates/script/generate +2 -0
  76. data/lib/generators/daemon_kit/capistrano/capistrano_generator.rb +21 -0
  77. data/{daemon_generators/deploy_capistrano → lib/generators/daemon_kit/capistrano}/templates/Capfile +0 -0
  78. data/{daemon_generators/deploy_capistrano → lib/generators/daemon_kit/capistrano}/templates/USAGE +0 -0
  79. data/{daemon_generators/deploy_capistrano/templates/config/deploy.rb → lib/generators/daemon_kit/capistrano/templates/config/deploy.rb.tt} +1 -1
  80. data/lib/generators/daemon_kit/capistrano/templates/config/deploy/production.rb.tt +6 -0
  81. data/lib/generators/daemon_kit/capistrano/templates/config/deploy/staging.rb.tt +6 -0
  82. data/{daemon_generators/deploy_capistrano → lib/generators/daemon_kit/capistrano}/templates/config/environments/staging.rb +0 -0
  83. data/{daemon_generators → lib/generators/daemon_kit}/cron/USAGE +0 -0
  84. data/lib/generators/daemon_kit/cron/cron_generator.rb +24 -0
  85. data/{daemon_generators/cron/templates/config/initializers → lib/generators/daemon_kit/cron/templates/config/pre-daemonize}/cron.rb +0 -0
  86. data/{daemon_generators/cron/templates/libexec/daemon.rb → lib/generators/daemon_kit/cron/templates/libexec/%app_name%-daemon.rb} +0 -0
  87. data/{daemon_generators → lib/generators/daemon_kit}/cucumber/USAGE +0 -0
  88. data/lib/generators/daemon_kit/cucumber/cucumber_generator.rb +45 -0
  89. data/{daemon_generators/cucumber/templates/cucumber_environment.rb → lib/generators/daemon_kit/cucumber/templates/config/environments/cucumber.rb} +0 -0
  90. data/lib/generators/daemon_kit/cucumber/templates/features/step_definitions/.empty_directory +0 -0
  91. data/{daemon_generators/cucumber/templates → lib/generators/daemon_kit/cucumber/templates/features/support}/env.rb +0 -0
  92. data/{daemon_generators/cucumber/templates → lib/generators/daemon_kit/cucumber/templates/script}/cucumber +1 -2
  93. data/{daemon_generators/cucumber/templates → lib/generators/daemon_kit/cucumber/templates/tasks}/cucumber.rake +0 -0
  94. data/{daemon_generators/jabber → lib/generators/daemon_kit/nanite_agent}/USAGE +0 -0
  95. data/lib/generators/daemon_kit/nanite_agent/nanite_agent_generator.rb +29 -0
  96. data/{daemon_generators → lib/generators/daemon_kit}/nanite_agent/templates/config/nanite.yml +0 -0
  97. data/{daemon_generators/nanite_agent/templates/config/initializers → lib/generators/daemon_kit/nanite_agent/templates/config/pre-daemonize}/nanite_agent.rb +0 -0
  98. data/{daemon_generators → lib/generators/daemon_kit}/nanite_agent/templates/lib/actors/sample.rb +0 -0
  99. data/{daemon_generators/nanite_agent/templates/libexec/daemon.rb → lib/generators/daemon_kit/nanite_agent/templates/libexec/%app_name%-daemon.rb} +0 -0
  100. data/{daemon_generators/nanite_agent → lib/generators/daemon_kit/rspec}/USAGE +0 -0
  101. data/lib/generators/daemon_kit/rspec/rspec_generator.rb +20 -0
  102. data/{daemon_generators/rspec/templates/spec.rb → lib/generators/daemon_kit/rspec/templates/spec/%app_name%_spec.rb} +0 -0
  103. data/{daemon_generators → lib/generators/daemon_kit}/rspec/templates/spec/spec.opts +0 -0
  104. data/{daemon_generators → lib/generators/daemon_kit}/rspec/templates/spec/spec_helper.rb +0 -0
  105. data/{daemon_generators → lib/generators/daemon_kit}/rspec/templates/tasks/rspec.rake +0 -0
  106. data/{daemon_generators/rspec → lib/generators/daemon_kit/ruote}/USAGE +0 -0
  107. data/lib/generators/daemon_kit/ruote/ruote_generator.rb +29 -0
  108. data/{daemon_generators → lib/generators/daemon_kit}/ruote/templates/config/amqp.yml +0 -0
  109. data/{daemon_generators/ruote/templates/config/initializers → lib/generators/daemon_kit/ruote/templates/config/pre-daemonize}/ruote.rb +0 -0
  110. data/{daemon_generators → lib/generators/daemon_kit}/ruote/templates/config/ruote.yml +0 -0
  111. data/{daemon_generators/ruote/templates/lib/daemon.rb → lib/generators/daemon_kit/ruote/templates/lib/%app_name%.rb} +0 -0
  112. data/{daemon_generators → lib/generators/daemon_kit}/ruote/templates/lib/sample.rb +0 -0
  113. data/{daemon_generators/ruote/templates/libexec/daemon.rb → lib/generators/daemon_kit/ruote/templates/libexec/%app_name%-daemon.rb} +0 -0
  114. data/{daemon_generators/ruote → lib/generators/daemon_kit/test_unit}/USAGE +0 -0
  115. data/{daemon_generators → lib/generators/daemon_kit}/test_unit/templates/tasks/test_unit.rake +0 -0
  116. data/{daemon_generators/test_unit/templates/test/test.rb → lib/generators/daemon_kit/test_unit/templates/test/%app_name%_test.rb.tt} +1 -1
  117. data/{daemon_generators → lib/generators/daemon_kit}/test_unit/templates/test/test_helper.rb +0 -0
  118. data/lib/generators/daemon_kit/test_unit/test_unit_generator.rb +20 -0
  119. data/lib/generators/daemon_kit/xmpp/templates/config/pre-daemonize/xmpp.rb +6 -0
  120. data/{daemon_generators/jabber/templates/config/jabber.yml → lib/generators/daemon_kit/xmpp/templates/config/xmpp.yml} +5 -2
  121. data/lib/generators/daemon_kit/xmpp/templates/libexec/%app_name%-daemon.rb +27 -0
  122. data/lib/generators/daemon_kit/xmpp/xmpp_generator.rb +24 -0
  123. data/spec/argument_spec.rb +1 -1
  124. data/spec/config_spec.rb +7 -3
  125. metadata +110 -86
  126. data/app_generators/daemon_kit/daemon_kit_generator.rb +0 -178
  127. data/app_generators/daemon_kit/templates/bin/daemon.erb +0 -7
  128. data/app_generators/daemon_kit/templates/script/destroy +0 -14
  129. data/app_generators/daemon_kit/templates/script/generate +0 -14
  130. data/daemon_generators/amqp/amqp_generator.rb +0 -65
  131. data/daemon_generators/cron/cron_generator.rb +0 -64
  132. data/daemon_generators/cucumber/cucumber_generator.rb +0 -38
  133. data/daemon_generators/deploy_capistrano/deploy_capistrano_generator.rb +0 -35
  134. data/daemon_generators/deploy_capistrano/templates/config/deploy/production.rb +0 -6
  135. data/daemon_generators/deploy_capistrano/templates/config/deploy/staging.rb +0 -6
  136. data/daemon_generators/jabber/jabber_generator.rb +0 -65
  137. data/daemon_generators/jabber/templates/config/initializers/jabber.rb +0 -7
  138. data/daemon_generators/jabber/templates/libexec/daemon.rb +0 -27
  139. data/daemon_generators/nanite_agent/nanite_agent_generator.rb +0 -68
  140. data/daemon_generators/rspec/rspec_generator.rb +0 -55
  141. data/daemon_generators/ruote/ruote_generator.rb +0 -67
  142. data/daemon_generators/test_unit/USAGE +0 -5
  143. data/daemon_generators/test_unit/test_unit_generator.rb +0 -51
  144. data/test/test_jabber_generator.rb +0 -49
@@ -0,0 +1,101 @@
1
+ require 'thor/actions/empty_directory'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Injects the given content into a file. Different from gsub_file, this
7
+ # method is reversible.
8
+ #
9
+ # ==== Parameters
10
+ # destination<String>:: Relative path to the destination root
11
+ # data<String>:: Data to add to the file. Can be given as a block.
12
+ # config<Hash>:: give :verbose => false to not log the status and the flag
13
+ # for injection (:after or :before).
14
+ #
15
+ # ==== Examples
16
+ #
17
+ # inject_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
18
+ #
19
+ # inject_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
20
+ # gems = ask "Which gems would you like to add?"
21
+ # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
22
+ # end
23
+ #
24
+ def inject_into_file(destination, *args, &block)
25
+ if block_given?
26
+ data, config = block, args.shift
27
+ else
28
+ data, config = args.shift, args.shift
29
+ end
30
+ action InjectIntoFile.new(self, destination, data, config)
31
+ end
32
+
33
+ class InjectIntoFile < EmptyDirectory #:nodoc:
34
+ attr_reader :replacement, :flag, :behavior
35
+
36
+ def initialize(base, destination, data, config)
37
+ super(base, destination, { :verbose => true }.merge(config))
38
+
39
+ @behavior, @flag = if @config.key?(:after)
40
+ [:after, @config.delete(:after)]
41
+ else
42
+ [:before, @config.delete(:before)]
43
+ end
44
+
45
+ @replacement = data.is_a?(Proc) ? data.call : data
46
+ @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
47
+ end
48
+
49
+ def invoke!
50
+ say_status :invoke
51
+
52
+ content = if @behavior == :after
53
+ '\0' + replacement
54
+ else
55
+ replacement + '\0'
56
+ end
57
+
58
+ replace!(/#{flag}/, content)
59
+ end
60
+
61
+ def revoke!
62
+ say_status :revoke
63
+
64
+ regexp = if @behavior == :after
65
+ content = '\1\2'
66
+ /(#{flag})(.*)(#{Regexp.escape(replacement)})/m
67
+ else
68
+ content = '\2\3'
69
+ /(#{Regexp.escape(replacement)})(.*)(#{flag})/m
70
+ end
71
+
72
+ replace!(regexp, content)
73
+ end
74
+
75
+ protected
76
+
77
+ def say_status(behavior)
78
+ status = if flag == /\A/
79
+ behavior == :invoke ? :prepend : :unprepend
80
+ elsif flag == /\z/
81
+ behavior == :invoke ? :append : :unappend
82
+ else
83
+ behavior == :invoke ? :inject : :deinject
84
+ end
85
+
86
+ super(status, config[:verbose])
87
+ end
88
+
89
+ # Adds the content to the file.
90
+ #
91
+ def replace!(regexp, string)
92
+ unless base.options[:pretend]
93
+ content = File.binread(destination)
94
+ content.gsub!(regexp, string)
95
+ File.open(destination, 'wb') { |file| file.write(content) }
96
+ end
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,515 @@
1
+ require 'thor/core_ext/hash_with_indifferent_access'
2
+ require 'thor/core_ext/ordered_hash'
3
+ require 'thor/error'
4
+ require 'thor/shell'
5
+ require 'thor/invocation'
6
+ require 'thor/parser'
7
+ require 'thor/task'
8
+ require 'thor/util'
9
+
10
+ class Thor
11
+ # Shortcuts for help.
12
+ HELP_MAPPINGS = %w(-h -? --help -D)
13
+
14
+ # Thor methods that should not be overwritten by the user.
15
+ THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
16
+ action add_file create_file in_root inside run run_ruby_script)
17
+
18
+ module Base
19
+ attr_accessor :options
20
+
21
+ # It receives arguments in an Array and two hashes, one for options and
22
+ # other for configuration.
23
+ #
24
+ # Notice that it does not check if all required arguments were supplied.
25
+ # It should be done by the parser.
26
+ #
27
+ # ==== Parameters
28
+ # args<Array[Object]>:: An array of objects. The objects are applied to their
29
+ # respective accessors declared with <tt>argument</tt>.
30
+ #
31
+ # options<Hash>:: An options hash that will be available as self.options.
32
+ # The hash given is converted to a hash with indifferent
33
+ # access, magic predicates (options.skip?) and then frozen.
34
+ #
35
+ # config<Hash>:: Configuration for this Thor class.
36
+ #
37
+ def initialize(args=[], options={}, config={})
38
+ Thor::Arguments.parse(self.class.arguments, args).each do |key, value|
39
+ send("#{key}=", value)
40
+ end
41
+
42
+ parse_options = self.class.class_options
43
+
44
+ if options.is_a?(Array)
45
+ task_options = config.delete(:task_options) # hook for start
46
+ parse_options = parse_options.merge(task_options) if task_options
47
+ array_options, hash_options = options, {}
48
+ else
49
+ array_options, hash_options = [], options
50
+ end
51
+
52
+ options = Thor::Options.parse(parse_options, array_options)
53
+ self.options = Thor::CoreExt::HashWithIndifferentAccess.new(options).merge!(hash_options)
54
+ self.options.freeze
55
+ end
56
+
57
+ class << self
58
+ def included(base) #:nodoc:
59
+ base.send :extend, ClassMethods
60
+ base.send :include, Invocation
61
+ base.send :include, Shell
62
+ end
63
+
64
+ # Returns the classes that inherits from Thor or Thor::Group.
65
+ #
66
+ # ==== Returns
67
+ # Array[Class]
68
+ #
69
+ def subclasses
70
+ @subclasses ||= []
71
+ end
72
+
73
+ # Returns the files where the subclasses are kept.
74
+ #
75
+ # ==== Returns
76
+ # Hash[path<String> => Class]
77
+ #
78
+ def subclass_files
79
+ @subclass_files ||= Hash.new{ |h,k| h[k] = [] }
80
+ end
81
+
82
+ # Whenever a class inherits from Thor or Thor::Group, we should track the
83
+ # class and the file on Thor::Base. This is the method responsable for it.
84
+ #
85
+ def register_klass_file(klass) #:nodoc:
86
+ file = caller[1].match(/(.*):\d+/)[1]
87
+ Thor::Base.subclasses << klass unless Thor::Base.subclasses.include?(klass)
88
+
89
+ file_subclasses = Thor::Base.subclass_files[File.expand_path(file)]
90
+ file_subclasses << klass unless file_subclasses.include?(klass)
91
+ end
92
+ end
93
+
94
+ module ClassMethods
95
+ attr_accessor :debugging
96
+
97
+ # Adds an argument to the class and creates an attr_accessor for it.
98
+ #
99
+ # Arguments are different from options in several aspects. The first one
100
+ # is how they are parsed from the command line, arguments are retrieved
101
+ # from position:
102
+ #
103
+ # thor task NAME
104
+ #
105
+ # Instead of:
106
+ #
107
+ # thor task --name=NAME
108
+ #
109
+ # Besides, arguments are used inside your code as an accessor (self.argument),
110
+ # while options are all kept in a hash (self.options).
111
+ #
112
+ # Finally, arguments cannot have type :default or :boolean but can be
113
+ # optional (supplying :optional => :true or :required => false), although
114
+ # you cannot have a required argument after a non-required argument. If you
115
+ # try it, an error is raised.
116
+ #
117
+ # ==== Parameters
118
+ # name<Symbol>:: The name of the argument.
119
+ # options<Hash>:: Described below.
120
+ #
121
+ # ==== Options
122
+ # :desc - Description for the argument.
123
+ # :required - If the argument is required or not.
124
+ # :optional - If the argument is optional or not.
125
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric.
126
+ # :default - Default value for this argument. It cannot be required and have default values.
127
+ # :banner - String to show on usage notes.
128
+ #
129
+ # ==== Errors
130
+ # ArgumentError:: Raised if you supply a required argument after a non required one.
131
+ #
132
+ def argument(name, options={})
133
+ is_thor_reserved_word?(name, :argument)
134
+ no_tasks { attr_accessor name }
135
+
136
+ required = if options.key?(:optional)
137
+ !options[:optional]
138
+ elsif options.key?(:required)
139
+ options[:required]
140
+ else
141
+ options[:default].nil?
142
+ end
143
+
144
+ remove_argument name
145
+
146
+ arguments.each do |argument|
147
+ next if argument.required?
148
+ raise ArgumentError, "You cannot have #{name.to_s.inspect} as required argument after " <<
149
+ "the non-required argument #{argument.human_name.inspect}."
150
+ end if required
151
+
152
+ arguments << Thor::Argument.new(name, options[:desc], required, options[:type],
153
+ options[:default], options[:banner])
154
+ end
155
+
156
+ # Returns this class arguments, looking up in the ancestors chain.
157
+ #
158
+ # ==== Returns
159
+ # Array[Thor::Argument]
160
+ #
161
+ def arguments
162
+ @arguments ||= from_superclass(:arguments, [])
163
+ end
164
+
165
+ # Adds a bunch of options to the set of class options.
166
+ #
167
+ # class_options :foo => false, :bar => :required, :baz => :string
168
+ #
169
+ # If you prefer more detailed declaration, check class_option.
170
+ #
171
+ # ==== Parameters
172
+ # Hash[Symbol => Object]
173
+ #
174
+ def class_options(options=nil)
175
+ @class_options ||= from_superclass(:class_options, {})
176
+ build_options(options, @class_options) if options
177
+ @class_options
178
+ end
179
+
180
+ # Adds an option to the set of class options
181
+ #
182
+ # ==== Parameters
183
+ # name<Symbol>:: The name of the argument.
184
+ # options<Hash>:: Described below.
185
+ #
186
+ # ==== Options
187
+ # :desc - Description for the argument.
188
+ # :required - If the argument is required or not.
189
+ # :default - Default value for this argument.
190
+ # :group - The group for this options. Use by class options to output options in different levels.
191
+ # :aliases - Aliases for this option.
192
+ # :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
193
+ # :banner - String to show on usage notes.
194
+ #
195
+ def class_option(name, options={})
196
+ build_option(name, options, class_options)
197
+ end
198
+
199
+ # Removes a previous defined argument. If :undefine is given, undefine
200
+ # accessors as well.
201
+ #
202
+ # ==== Paremeters
203
+ # names<Array>:: Arguments to be removed
204
+ #
205
+ # ==== Examples
206
+ #
207
+ # remove_argument :foo
208
+ # remove_argument :foo, :bar, :baz, :undefine => true
209
+ #
210
+ def remove_argument(*names)
211
+ options = names.last.is_a?(Hash) ? names.pop : {}
212
+
213
+ names.each do |name|
214
+ arguments.delete_if { |a| a.name == name.to_s }
215
+ undef_method name, "#{name}=" if options[:undefine]
216
+ end
217
+ end
218
+
219
+ # Removes a previous defined class option.
220
+ #
221
+ # ==== Paremeters
222
+ # names<Array>:: Class options to be removed
223
+ #
224
+ # ==== Examples
225
+ #
226
+ # remove_class_option :foo
227
+ # remove_class_option :foo, :bar, :baz
228
+ #
229
+ def remove_class_option(*names)
230
+ names.each do |name|
231
+ class_options.delete(name)
232
+ end
233
+ end
234
+
235
+ # Defines the group. This is used when thor list is invoked so you can specify
236
+ # that only tasks from a pre-defined group will be shown. Defaults to standard.
237
+ #
238
+ # ==== Parameters
239
+ # name<String|Symbol>
240
+ #
241
+ def group(name=nil)
242
+ case name
243
+ when nil
244
+ @group ||= from_superclass(:group, 'standard')
245
+ else
246
+ @group = name.to_s
247
+ end
248
+ end
249
+
250
+ # Returns the tasks for this Thor class.
251
+ #
252
+ # ==== Returns
253
+ # OrderedHash:: An ordered hash with tasks names as keys and Thor::Task
254
+ # objects as values.
255
+ #
256
+ def tasks
257
+ @tasks ||= Thor::CoreExt::OrderedHash.new
258
+ end
259
+
260
+ # Returns the tasks for this Thor class and all subclasses.
261
+ #
262
+ # ==== Returns
263
+ # OrderedHash:: An ordered hash with tasks names as keys and Thor::Task
264
+ # objects as values.
265
+ #
266
+ def all_tasks
267
+ @all_tasks ||= from_superclass(:all_tasks, Thor::CoreExt::OrderedHash.new)
268
+ @all_tasks.merge(tasks)
269
+ end
270
+
271
+ # Removes a given task from this Thor class. This is usually done if you
272
+ # are inheriting from another class and don't want it to be available
273
+ # anymore.
274
+ #
275
+ # By default it only remove the mapping to the task. But you can supply
276
+ # :undefine => true to undefine the method from the class as well.
277
+ #
278
+ # ==== Parameters
279
+ # name<Symbol|String>:: The name of the task to be removed
280
+ # options<Hash>:: You can give :undefine => true if you want tasks the method
281
+ # to be undefined from the class as well.
282
+ #
283
+ def remove_task(*names)
284
+ options = names.last.is_a?(Hash) ? names.pop : {}
285
+
286
+ names.each do |name|
287
+ tasks.delete(name.to_s)
288
+ all_tasks.delete(name.to_s)
289
+ undef_method name if options[:undefine]
290
+ end
291
+ end
292
+
293
+ # All methods defined inside the given block are not added as tasks.
294
+ #
295
+ # So you can do:
296
+ #
297
+ # class MyScript < Thor
298
+ # no_tasks do
299
+ # def this_is_not_a_task
300
+ # end
301
+ # end
302
+ # end
303
+ #
304
+ # You can also add the method and remove it from the task list:
305
+ #
306
+ # class MyScript < Thor
307
+ # def this_is_not_a_task
308
+ # end
309
+ # remove_task :this_is_not_a_task
310
+ # end
311
+ #
312
+ def no_tasks
313
+ @no_tasks = true
314
+ yield
315
+ @no_tasks = false
316
+ end
317
+
318
+ # Sets the namespace for the Thor or Thor::Group class. By default the
319
+ # namespace is retrieved from the class name. If your Thor class is named
320
+ # Scripts::MyScript, the help method, for example, will be called as:
321
+ #
322
+ # thor scripts:my_script -h
323
+ #
324
+ # If you change the namespace:
325
+ #
326
+ # namespace :my_scripts
327
+ #
328
+ # You change how your tasks are invoked:
329
+ #
330
+ # thor my_scripts -h
331
+ #
332
+ # Finally, if you change your namespace to default:
333
+ #
334
+ # namespace :default
335
+ #
336
+ # Your tasks can be invoked with a shortcut. Instead of:
337
+ #
338
+ # thor :my_task
339
+ #
340
+ def namespace(name=nil)
341
+ case name
342
+ when nil
343
+ @namespace ||= Thor::Util.namespace_from_thor_class(self, false)
344
+ else
345
+ @namespace = name.to_s
346
+ end
347
+ end
348
+
349
+ # Default way to start generators from the command line.
350
+ #
351
+ def start(given_args=ARGV, config={})
352
+ self.debugging = given_args.include?("--debug")
353
+ config[:shell] ||= Thor::Base.shell.new
354
+ yield
355
+ rescue Thor::Error => e
356
+ if debugging
357
+ raise e
358
+ else
359
+ config[:shell].error e.message
360
+ end
361
+ exit(1) if exit_on_failure?
362
+ end
363
+
364
+ protected
365
+
366
+ # Prints the class options per group. If an option does not belong to
367
+ # any group, it's printed as Class option.
368
+ #
369
+ def class_options_help(shell, groups={}) #:nodoc:
370
+ # Group options by group
371
+ class_options.each do |_, value|
372
+ groups[value.group] ||= []
373
+ groups[value.group] << value
374
+ end
375
+
376
+ # Deal with default group
377
+ global_options = groups.delete(nil) || []
378
+ print_options(shell, global_options)
379
+
380
+ # Print all others
381
+ groups.each do |group_name, options|
382
+ print_options(shell, options, group_name)
383
+ end
384
+ end
385
+
386
+ # Receives a set of options and print them.
387
+ def print_options(shell, options, group_name=nil)
388
+ return if options.empty?
389
+
390
+ list = []
391
+ padding = options.collect{ |o| o.aliases.size }.max.to_i * 4
392
+
393
+ options.each do |option|
394
+ item = [ option.usage(padding) ]
395
+ item.push(option.description ? "# #{option.description}" : "")
396
+
397
+ list << item
398
+ list << [ "", "# Default: #{option.default}" ] if option.show_default?
399
+ end
400
+
401
+ shell.say(group_name ? "#{group_name} options:" : "Options:")
402
+ shell.print_table(list, :ident => 2)
403
+ shell.say ""
404
+ end
405
+
406
+ # Raises an error if the word given is a Thor reserved word.
407
+ #
408
+ def is_thor_reserved_word?(word, type) #:nodoc:
409
+ return false unless THOR_RESERVED_WORDS.include?(word.to_s)
410
+ raise "#{word.inspect} is a Thor reserved word and cannot be defined as #{type}"
411
+ end
412
+
413
+ # Build an option and adds it to the given scope.
414
+ #
415
+ # ==== Parameters
416
+ # name<Symbol>:: The name of the argument.
417
+ # options<Hash>:: Described in both class_option and method_option.
418
+ #
419
+ def build_option(name, options, scope) #:nodoc:
420
+ scope[name] = Thor::Option.new(name, options[:desc], options[:required],
421
+ options[:type], options[:default], options[:banner],
422
+ options[:group], options[:aliases])
423
+ end
424
+
425
+ # Receives a hash of options, parse them and add to the scope. This is a
426
+ # fast way to set a bunch of options:
427
+ #
428
+ # build_options :foo => true, :bar => :required, :baz => :string
429
+ #
430
+ # ==== Parameters
431
+ # Hash[Symbol => Object]
432
+ #
433
+ def build_options(options, scope) #:nodoc:
434
+ options.each do |key, value|
435
+ scope[key] = Thor::Option.parse(key, value)
436
+ end
437
+ end
438
+
439
+ # Finds a task with the given name. If the task belongs to the current
440
+ # class, just return it, otherwise dup it and add the fresh copy to the
441
+ # current task hash.
442
+ #
443
+ def find_and_refresh_task(name) #:nodoc:
444
+ task = if task = tasks[name.to_s]
445
+ task
446
+ elsif task = all_tasks[name.to_s]
447
+ tasks[name.to_s] = task.clone
448
+ else
449
+ raise ArgumentError, "You supplied :for => #{name.inspect}, but the task #{name.inspect} could not be found."
450
+ end
451
+ end
452
+
453
+ # Everytime someone inherits from a Thor class, register the klass
454
+ # and file into baseclass.
455
+ #
456
+ def inherited(klass)
457
+ Thor::Base.register_klass_file(klass)
458
+ end
459
+
460
+ # Fire this callback whenever a method is added. Added methods are
461
+ # tracked as tasks by invoking the create_task method.
462
+ #
463
+ def method_added(meth)
464
+ meth = meth.to_s
465
+
466
+ if meth == "initialize"
467
+ initialize_added
468
+ return
469
+ end
470
+
471
+ # Return if it's not a public instance method
472
+ return unless public_instance_methods.include?(meth) ||
473
+ public_instance_methods.include?(meth.to_sym)
474
+
475
+ return if @no_tasks || !create_task(meth)
476
+
477
+ is_thor_reserved_word?(meth, :task)
478
+ Thor::Base.register_klass_file(self)
479
+ end
480
+
481
+ # Retrieves a value from superclass. If it reaches the baseclass,
482
+ # returns default.
483
+ #
484
+ def from_superclass(method, default=nil)
485
+ if self == baseclass || !superclass.respond_to?(method, true)
486
+ default
487
+ else
488
+ value = superclass.send(method)
489
+ value.dup if value
490
+ end
491
+ end
492
+
493
+ # A flag that makes the process exit with status 1 if any error happens.
494
+ #
495
+ def exit_on_failure?
496
+ false
497
+ end
498
+
499
+ # SIGNATURE: Sets the baseclass. This is where the superclass lookup
500
+ # finishes.
501
+ def baseclass #:nodoc:
502
+ end
503
+
504
+ # SIGNATURE: Creates a new task if valid_task? is true. This method is
505
+ # called when a new method is added to the class.
506
+ def create_task(meth) #:nodoc:
507
+ end
508
+
509
+ # SIGNATURE: Defines behavior when the initialize method is added to the
510
+ # class.
511
+ def initialize_added #:nodoc:
512
+ end
513
+ end
514
+ end
515
+ end