wycats-thor 0.9.8 → 0.10.26

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ class Thor
2
+ # Creates an install task.
3
+ #
4
+ # ==== Parameters
5
+ # spec<Gem::Specification>
6
+ #
7
+ # ==== Options
8
+ # :dir - The directory where the package is hold before installation. Defaults to ./pkg.
9
+ #
10
+ def self.install_task(spec, options={})
11
+ package_task(spec, options)
12
+ tasks['install'] = Thor::InstallTask.new(spec, options)
13
+ end
14
+
15
+ class InstallTask < Task
16
+ attr_accessor :spec, :config
17
+
18
+ def initialize(gemspec, config={})
19
+ super(:install, "Install the gem", "install", {})
20
+ @spec = gemspec
21
+ @config = { :dir => File.join(Dir.pwd, "pkg") }.merge(config)
22
+ end
23
+
24
+ def run(instance, args=[])
25
+ null, sudo, gem = RUBY_PLATFORM =~ /mswin|mingw/ ? ['NUL', '', 'gem.bat'] :
26
+ ['/dev/null', 'sudo', 'gem']
27
+
28
+ old_stderr, $stderr = $stderr.dup, File.open(null, "w")
29
+ instance.invoke(:package)
30
+ $stderr = old_stderr
31
+
32
+ system %{#{sudo} #{Gem.ruby} -S #{gem} install #{config[:dir]}/#{spec.name}-#{spec.version} --no-rdoc --no-ri --no-update-sources}
33
+ end
34
+ end
35
+ end
@@ -1,18 +1,31 @@
1
- require "thor/task"
1
+ require "fileutils"
2
2
 
3
- class Thor::PackageTask < Thor::Task
4
- attr_accessor :spec
5
- attr_accessor :opts
6
-
7
- def initialize(gemspec, opts = {})
8
- super(:package, "build a gem package")
9
- @spec = gemspec
10
- @opts = {:dir => File.join(Dir.pwd, "pkg")}.merge(opts)
3
+ class Thor
4
+ # Creates a package task.
5
+ #
6
+ # ==== Parameters
7
+ # spec<Gem::Specification>
8
+ #
9
+ # ==== Options
10
+ # :dir - The package directory. Defaults to ./pkg.
11
+ #
12
+ def self.package_task(spec, options={})
13
+ tasks['package'] = Thor::PackageTask.new(spec, options)
11
14
  end
12
15
 
13
- def run
14
- FileUtils.mkdir_p(@opts[:dir])
15
- Gem::Builder.new(spec).build
16
- FileUtils.mv(spec.file_name, File.join(@opts[:dir], spec.file_name))
16
+ class PackageTask < Task
17
+ attr_accessor :spec, :config
18
+
19
+ def initialize(gemspec, config={})
20
+ super(:package, "Build a gem package", "package", {})
21
+ @spec = gemspec
22
+ @config = {:dir => File.join(Dir.pwd, "pkg")}.merge(config)
23
+ end
24
+
25
+ def run(instance, args=[])
26
+ FileUtils.mkdir_p(config[:dir])
27
+ Gem::Builder.new(spec).build
28
+ FileUtils.mv(spec.file_name, File.join(config[:dir], spec.file_name))
29
+ end
17
30
  end
18
31
  end
@@ -0,0 +1,70 @@
1
+ require "fileutils"
2
+
3
+ class Thor
4
+ # Creates a spec task.
5
+ #
6
+ # ==== Parameters
7
+ # files<Array> - Array of files to spec
8
+ #
9
+ # ==== Options
10
+ # :name - The name of the task. It can be rcov or spec. Spec is the default.
11
+ # :rcov - A hash with rcov specific options.
12
+ # :rcov_dir - Where rcov reports should be printed.
13
+ # :verbose - Sets the default value for verbose, although it can be specified
14
+ # also through the command line.
15
+ #
16
+ # All other options are added to rspec.
17
+ #
18
+ def self.spec_task(files, options={})
19
+ name = (options.delete(:name) || 'spec').to_s
20
+ tasks[name] = Thor::SpecTask.new(name, files, options)
21
+ end
22
+
23
+ class SpecTask < Task
24
+ attr_accessor :name, :files, :rcov_dir, :rcov_config, :spec_config
25
+
26
+ def initialize(name, files, config={})
27
+ options = { :verbose => Thor::Option.parse(:verbose, config.delete(:verbose) || false) }
28
+ super(name, "#{name.capitalize} task", name, options)
29
+
30
+ @name = name
31
+ @files = files.map{ |f| %["#{f}"] }.join(" ")
32
+ @rcov_dir = config.delete(:rdoc_dir) || File.join(Dir.pwd, 'coverage')
33
+ @rcov_config = config.delete(:rcov) || {}
34
+ @spec_config = { :format => 'specdoc', :color => true }.merge(config)
35
+ end
36
+
37
+ def run(instance, args=[])
38
+ rcov_opts = Thor::Options.to_switches(rcov_config)
39
+ spec_opts = Thor::Options.to_switches(spec_config)
40
+
41
+ require 'rbconfig'
42
+ cmd = RbConfig::CONFIG['ruby_install_name'] << " "
43
+
44
+ if rcov?
45
+ FileUtils.rm_rf(rcov_dir)
46
+ cmd << "-S #{where('rcov')} -o #{rcov_dir} #{rcov_opts} "
47
+ end
48
+
49
+ cmd << [where('spec'), rcov? ? " -- " : nil, files, spec_opts].join(" ")
50
+
51
+ puts cmd if instance.options.verbose?
52
+ system(cmd)
53
+ exit($?.exitstatus)
54
+ end
55
+
56
+ private
57
+
58
+ def rcov?
59
+ name == "rcov"
60
+ end
61
+
62
+ def where(file)
63
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
64
+ file_with_path = File.join(path, file)
65
+ next unless File.exist?(file_with_path) && File.executable?(file_with_path)
66
+ return File.expand_path(file_with_path)
67
+ end
68
+ end
69
+ end
70
+ end
data/lib/thor/tasks.rb CHANGED
@@ -1,77 +1,4 @@
1
- require "thor"
2
- require "fileutils"
3
-
4
- class Thor
5
- def self.package_task(spec)
6
- desc "package", "package up the gem"
7
- define_method :package do
8
- FileUtils.mkdir_p(File.join(Dir.pwd, "pkg"))
9
- Gem::Builder.new(spec).build
10
- FileUtils.mv(spec.file_name, File.join(Dir.pwd, "pkg", spec.file_name))
11
- end
12
- end
13
-
14
- def self.install_task(spec)
15
- package_task spec
16
-
17
- null, sudo, gem = RUBY_PLATFORM =~ /w(in)?32$/ ? ['NUL', '', 'gem.bat'] :
18
- ['/dev/null', 'sudo', 'gem']
19
-
20
- desc "install", "install the gem"
21
- define_method :install do
22
- old_stderr, $stderr = $stderr.dup, File.open(null, "w")
23
- package
24
- $stderr = old_stderr
25
- system %{#{sudo} #{gem} install pkg/#{spec.name}-#{spec.version} --no-rdoc --no-ri --no-update-sources}
26
- end
27
- end
28
-
29
- def self.spec_task(file_list, opts = {})
30
- name = opts.delete(:name) || "spec"
31
- rcov_dir = opts.delete(:rcov_dir) || "coverage"
32
- file_list = file_list.map {|f| %["#{f}"]}.join(" ")
33
- verbose = opts.delete(:verbose)
34
- opts = {:format => "specdoc", :color => true}.merge(opts)
35
-
36
- rcov_opts = convert_task_options(opts.delete(:rcov) || {})
37
- rcov = !rcov_opts.empty?
38
- options = convert_task_options(opts)
39
-
40
- if rcov
41
- FileUtils.rm_rf(File.join(Dir.pwd, rcov_dir))
42
- end
43
-
44
- desc(name, "spec task")
45
- define_method(name) do
46
- cmd = "ruby "
47
- if rcov
48
- cmd << "-S rcov -o #{rcov_dir} #{rcov_opts} "
49
- end
50
- cmd << `which spec`.chomp
51
- cmd << " -- " if rcov
52
- cmd << " "
53
- cmd << file_list
54
- cmd << " "
55
- cmd << options
56
- puts cmd if verbose
57
- system(cmd)
58
- exit($?.exitstatus)
59
- end
60
- end
61
-
62
- private
63
- def self.convert_task_options(opts)
64
- opts.map do |key, value|
65
- case value
66
- when true
67
- "--#{key}"
68
- when Array
69
- value.map {|v| "--#{key} #{v.inspect}"}.join(" ")
70
- when nil, false
71
- ""
72
- else
73
- "--#{key} #{value.inspect}"
74
- end
75
- end.join(" ")
76
- end
1
+ # This only loads all tasks inside tasks.
2
+ Dir[File.join(File.dirname(__FILE__), "tasks", "*.rb")].each do |task|
3
+ require task
77
4
  end
data/lib/thor/util.rb CHANGED
@@ -1,57 +1,229 @@
1
- require 'thor/error'
2
-
3
- module ObjectSpace
4
-
5
- class << self
6
-
7
- # @return <Array[Class]> All the classes in the object space.
8
- def classes
9
- klasses = []
10
- ObjectSpace.each_object(Class) {|o| klasses << o}
11
- klasses
12
- end
13
- end
14
-
15
- end
1
+ require 'rbconfig'
16
2
 
17
3
  class Thor
4
+ module Sandbox; end
5
+
6
+ # This module holds several utilities:
7
+ #
8
+ # 1) Methods to convert thor namespaces to constants and vice-versa.
9
+ #
10
+ # Thor::Utils.constant_to_namespace(Foo::Bar::Baz) #=> "foo:bar:baz"
11
+ # Thor::Utils.namespace_to_constant("foo:bar:baz") #=> Foo::Bar::Baz
12
+ #
13
+ # 2) Loading thor files and sandboxing:
14
+ #
15
+ # Thor::Utils.load_thorfile("~/.thor/foo")
16
+ #
18
17
  module Util
19
-
20
- def self.constant_to_thor_path(str, remove_default = true)
21
- str = snake_case(str.to_s).squeeze(":")
22
- str.gsub!(/^default/, '') if remove_default
23
- str
24
- end
25
18
 
26
- def self.constant_from_thor_path(str)
27
- make_constant(to_constant(str))
28
- rescue NameError => e
29
- raise e unless e.message =~ /^uninitialized constant (.*)$/
30
- raise Error, "There was no available namespace `#{str}'."
31
- end
19
+ # Receives a namespace and search for it in the Thor::Base subclasses.
20
+ #
21
+ # ==== Parameters
22
+ # namespace<String>:: The namespace to search for.
23
+ #
24
+ def self.find_by_namespace(namespace)
25
+ namespace = 'default' if namespace.empty?
32
26
 
33
- def self.to_constant(str)
34
- str = 'default' if str.empty?
35
- str.gsub(/:(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
27
+ Thor::Base.subclasses.find do |klass|
28
+ klass.namespace == namespace
29
+ end
36
30
  end
37
31
 
38
- def self.constants_in_contents(str)
39
- klasses = ObjectSpace.classes.dup
40
- Module.new.class_eval(str)
41
- klasses = ObjectSpace.classes - klasses
42
- klasses = klasses.select {|k| k < Thor }
43
- klasses.map! {|k| k.to_s.gsub(/#<Module:\w+>::/, '')}
32
+ # Receives a constant and converts it to a Thor namespace. Since Thor tasks
33
+ # can be added to a sandbox, this method is also responsable for removing
34
+ # the sandbox namespace.
35
+ #
36
+ # This method should not be used in general because it's used to deal with
37
+ # older versions of Thor. On current versions, if you need to get the
38
+ # namespace from a class, just call namespace on it.
39
+ #
40
+ # ==== Parameters
41
+ # constant<Object>:: The constant to be converted to the thor path.
42
+ #
43
+ # ==== Returns
44
+ # String:: If we receive Foo::Bar::Baz it returns "foo:bar:baz"
45
+ #
46
+ def self.constant_to_namespace(constant, remove_default=true)
47
+ constant = constant.to_s.gsub(/^Thor::Sandbox::/, "")
48
+ constant = snake_case(constant).squeeze(":")
49
+ constant.gsub!(/^default/, '') if remove_default
50
+ constant
44
51
  end
45
52
 
46
- def self.make_constant(str)
47
- list = str.split("::").inject(Object) {|obj, x| obj.const_get(x)}
53
+ # Given the contents, evaluate it inside the sandbox and returns the thor
54
+ # classes defined in the sandbox.
55
+ #
56
+ # ==== Parameters
57
+ # contents<String>
58
+ #
59
+ # ==== Returns
60
+ # Array[Object]
61
+ #
62
+ def self.namespaces_in_contents(contents, file=__FILE__)
63
+ old_constants = Thor::Base.subclasses.dup
64
+ Thor::Base.subclasses.clear
65
+
66
+ load_thorfile(file, contents)
67
+
68
+ new_constants = Thor::Base.subclasses.dup
69
+ Thor::Base.subclasses.replace(old_constants)
70
+
71
+ new_constants.map!{ |c| c.namespace }
72
+ new_constants.compact!
73
+ new_constants
48
74
  end
49
-
75
+
76
+ # Receives a string and convert it to snake case. SnakeCase returns snake_case.
77
+ #
78
+ # ==== Parameters
79
+ # String
80
+ #
81
+ # ==== Returns
82
+ # String
83
+ #
50
84
  def self.snake_case(str)
51
85
  return str.downcase if str =~ /^[A-Z_]+$/
52
86
  str.gsub(/\B[A-Z]/, '_\&').squeeze('_') =~ /_*(.*)/
53
87
  return $+.downcase
54
- end
55
-
88
+ end
89
+
90
+ # Receives a namespace and tries to retrieve a Thor or Thor::Group class
91
+ # from it. It first searches for a class using the all the given namespace,
92
+ # if it's not found, removes the highest entry and searches for the class
93
+ # again. If found, returns the highest entry as the class name.
94
+ #
95
+ # ==== Examples
96
+ #
97
+ # class Foo::Bar < Thor
98
+ # def baz
99
+ # end
100
+ # end
101
+ #
102
+ # class Baz::Foo < Thor::Group
103
+ # end
104
+ #
105
+ # Thor::Util.namespace_to_thor_class("foo:bar") #=> Foo::Bar, nil # will invoke default task
106
+ # Thor::Util.namespace_to_thor_class("baz:foo") #=> Baz::Foo, nil
107
+ # Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz"
108
+ #
109
+ # ==== Parameters
110
+ # namespace<String>
111
+ #
112
+ # ==== Errors
113
+ # Thor::Error:: raised if the namespace cannot be found.
114
+ #
115
+ # Thor::Error:: raised if the namespace evals to a class which does not
116
+ # inherit from Thor or Thor::Group.
117
+ #
118
+ def self.namespace_to_thor_class(namespace, raise_if_nil=true)
119
+ klass, task_name = Thor::Util.find_by_namespace(namespace), nil
120
+
121
+ if klass.nil? && namespace.include?(?:)
122
+ namespace = namespace.split(":")
123
+ task_name = namespace.pop
124
+ klass = Thor::Util.find_by_namespace(namespace.join(":"))
125
+ end
126
+
127
+ raise Error, "could not find Thor class or task '#{namespace}'" if raise_if_nil && klass.nil?
128
+
129
+ return klass, task_name
130
+ end
131
+
132
+ # Receives a path and load the thor file in the path. The file is evaluated
133
+ # inside the sandbox to avoid namespacing conflicts.
134
+ #
135
+ def self.load_thorfile(path, content=nil)
136
+ content ||= File.read(path)
137
+
138
+ begin
139
+ Thor::Sandbox.class_eval(content, path)
140
+ rescue Exception => e
141
+ $stderr.puts "WARNING: unable to load thorfile #{path.inspect}: #{e.message}"
142
+ end
143
+ end
144
+
145
+ # Receives a yaml (hash) and updates all constants entries to namespace.
146
+ # This was added to deal with deprecated versions of Thor.
147
+ #
148
+ # TODO Deprecate this method in the future.
149
+ #
150
+ # ==== Returns
151
+ # TrueClass|FalseClass:: Returns true if any change to the yaml file was made.
152
+ #
153
+ def self.convert_constants_to_namespaces(yaml)
154
+ yaml_changed = false
155
+
156
+ yaml.each do |k, v|
157
+ next unless v[:constants] && v[:namespaces].nil?
158
+ yaml_changed = true
159
+ yaml[k][:namespaces] = v[:constants].map{|c| Thor::Util.constant_to_namespace(c)}
160
+ end
161
+
162
+ yaml_changed
163
+ end
164
+
165
+ def self.user_home
166
+ @@user_home ||= if ENV["HOME"]
167
+ ENV["HOME"]
168
+ elsif ENV["USERPROFILE"]
169
+ ENV["USERPROFILE"]
170
+ elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
171
+ File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"])
172
+ elsif ENV["APPDATA"]
173
+ ENV["APPDATA"]
174
+ else
175
+ begin
176
+ File.expand_path("~")
177
+ rescue
178
+ if File::ALT_SEPARATOR
179
+ "C:/"
180
+ else
181
+ "/"
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ # Returns the root where thor files are located, dependending on the OS.
188
+ #
189
+ def self.thor_root
190
+ File.join(user_home, ".thor")
191
+ end
192
+
193
+ # Returns the files in the thor root. On Windows thor_root will be something
194
+ # like this:
195
+ #
196
+ # C:\Documents and Settings\james\.thor
197
+ #
198
+ # If we don't #gsub the \ character, Dir.glob will fail.
199
+ #
200
+ def self.thor_root_glob
201
+ files = Dir["#{thor_root.gsub(/\\/, '/')}/*"]
202
+
203
+ files.map! do |file|
204
+ File.directory?(file) ? File.join(file, "main.thor") : file
205
+ end
206
+ end
207
+
208
+ # Where to look for Thor files.
209
+ #
210
+ def self.globs_for(path)
211
+ ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
212
+ end
213
+
214
+ # Return the path to the ruby interpreter taking into account multiple
215
+ # installations and windows extensions.
216
+ #
217
+ def self.ruby_command #:nodoc:
218
+ @ruby_command ||= begin
219
+ ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
220
+ ruby << Config::CONFIG['EXEEXT']
221
+
222
+ # escape string in case path to ruby executable contain spaces.
223
+ ruby.sub!(/.*\s.*/m, '"\&"')
224
+ ruby
225
+ end
226
+ end
227
+
56
228
  end
57
229
  end