thor 0.16.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +15 -0
  3. data/README.md +23 -6
  4. data/bin/thor +1 -1
  5. data/lib/thor/actions/create_file.rb +34 -35
  6. data/lib/thor/actions/create_link.rb +9 -5
  7. data/lib/thor/actions/directory.rb +33 -23
  8. data/lib/thor/actions/empty_directory.rb +75 -85
  9. data/lib/thor/actions/file_manipulation.rb +103 -36
  10. data/lib/thor/actions/inject_into_file.rb +46 -36
  11. data/lib/thor/actions.rb +90 -68
  12. data/lib/thor/base.rb +302 -244
  13. data/lib/thor/command.rb +142 -0
  14. data/lib/thor/core_ext/hash_with_indifferent_access.rb +52 -24
  15. data/lib/thor/error.rb +90 -10
  16. data/lib/thor/group.rb +70 -74
  17. data/lib/thor/invocation.rb +63 -55
  18. data/lib/thor/line_editor/basic.rb +37 -0
  19. data/lib/thor/line_editor/readline.rb +88 -0
  20. data/lib/thor/line_editor.rb +17 -0
  21. data/lib/thor/nested_context.rb +29 -0
  22. data/lib/thor/parser/argument.rb +24 -28
  23. data/lib/thor/parser/arguments.rb +110 -102
  24. data/lib/thor/parser/option.rb +53 -15
  25. data/lib/thor/parser/options.rb +174 -97
  26. data/lib/thor/parser.rb +4 -4
  27. data/lib/thor/rake_compat.rb +12 -11
  28. data/lib/thor/runner.rb +159 -155
  29. data/lib/thor/shell/basic.rb +216 -93
  30. data/lib/thor/shell/color.rb +53 -40
  31. data/lib/thor/shell/html.rb +61 -58
  32. data/lib/thor/shell.rb +29 -36
  33. data/lib/thor/util.rb +231 -213
  34. data/lib/thor/version.rb +1 -1
  35. data/lib/thor.rb +303 -166
  36. data/thor.gemspec +27 -24
  37. metadata +36 -226
  38. data/.gitignore +0 -44
  39. data/.rspec +0 -2
  40. data/.travis.yml +0 -7
  41. data/CHANGELOG.rdoc +0 -134
  42. data/Gemfile +0 -15
  43. data/Thorfile +0 -30
  44. data/bin/rake2thor +0 -86
  45. data/lib/thor/core_ext/dir_escape.rb +0 -0
  46. data/lib/thor/core_ext/file_binary_read.rb +0 -9
  47. data/lib/thor/core_ext/ordered_hash.rb +0 -100
  48. data/lib/thor/task.rb +0 -132
  49. data/spec/actions/create_file_spec.rb +0 -170
  50. data/spec/actions/create_link_spec.rb +0 -81
  51. data/spec/actions/directory_spec.rb +0 -149
  52. data/spec/actions/empty_directory_spec.rb +0 -130
  53. data/spec/actions/file_manipulation_spec.rb +0 -370
  54. data/spec/actions/inject_into_file_spec.rb +0 -135
  55. data/spec/actions_spec.rb +0 -331
  56. data/spec/base_spec.rb +0 -279
  57. data/spec/core_ext/hash_with_indifferent_access_spec.rb +0 -43
  58. data/spec/core_ext/ordered_hash_spec.rb +0 -115
  59. data/spec/exit_condition_spec.rb +0 -19
  60. data/spec/fixtures/application.rb +0 -2
  61. data/spec/fixtures/app{1}/README +0 -3
  62. data/spec/fixtures/bundle/execute.rb +0 -6
  63. data/spec/fixtures/bundle/main.thor +0 -1
  64. data/spec/fixtures/doc/%file_name%.rb.tt +0 -1
  65. data/spec/fixtures/doc/COMMENTER +0 -10
  66. data/spec/fixtures/doc/README +0 -3
  67. data/spec/fixtures/doc/block_helper.rb +0 -3
  68. data/spec/fixtures/doc/components/.empty_directory +0 -0
  69. data/spec/fixtures/doc/config.rb +0 -1
  70. data/spec/fixtures/doc/config.yaml.tt +0 -1
  71. data/spec/fixtures/enum.thor +0 -10
  72. data/spec/fixtures/group.thor +0 -114
  73. data/spec/fixtures/invoke.thor +0 -112
  74. data/spec/fixtures/path with spaces +0 -0
  75. data/spec/fixtures/script.thor +0 -190
  76. data/spec/fixtures/task.thor +0 -10
  77. data/spec/group_spec.rb +0 -216
  78. data/spec/invocation_spec.rb +0 -100
  79. data/spec/parser/argument_spec.rb +0 -53
  80. data/spec/parser/arguments_spec.rb +0 -66
  81. data/spec/parser/option_spec.rb +0 -202
  82. data/spec/parser/options_spec.rb +0 -330
  83. data/spec/rake_compat_spec.rb +0 -72
  84. data/spec/register_spec.rb +0 -135
  85. data/spec/runner_spec.rb +0 -241
  86. data/spec/shell/basic_spec.rb +0 -300
  87. data/spec/shell/color_spec.rb +0 -81
  88. data/spec/shell/html_spec.rb +0 -32
  89. data/spec/shell_spec.rb +0 -47
  90. data/spec/spec_helper.rb +0 -59
  91. data/spec/task_spec.rb +0 -80
  92. data/spec/thor_spec.rb +0 -418
  93. data/spec/util_spec.rb +0 -196
data/bin/rake2thor DELETED
@@ -1,86 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'ruby2ruby'
4
- require 'parse_tree'
5
- if Ruby2Ruby::VERSION >= "1.2.0"
6
- require 'parse_tree_extensions'
7
- end
8
- require 'rake'
9
-
10
- input = ARGV[0] || 'Rakefile'
11
- output = ARGV[1] || 'Thorfile'
12
-
13
- $requires = []
14
-
15
- module Kernel
16
- def require_with_record(file)
17
- $requires << file if caller[1] =~ /rake2thor:/
18
- require_without_record file
19
- end
20
- alias_method :require_without_record, :require
21
- alias_method :require, :require_with_record
22
- end
23
-
24
- load input
25
-
26
- @private_methods = []
27
-
28
- def file_task_name(name)
29
- "compile_" + name.gsub('/', '_slash_').gsub('.', '_dot_').gsub(/\W/, '_')
30
- end
31
-
32
- def method_for_task(task)
33
- file_task = task.is_a?(Rake::FileTask)
34
- comment = task.instance_variable_get('@comment')
35
- prereqs = task.instance_variable_get('@prerequisites').select(&Rake::Task.method(:task_defined?))
36
- actions = task.instance_variable_get('@actions')
37
- name = task.name.gsub(/^([^:]+:)+/, '')
38
- name = file_task_name(name) if file_task
39
- meth = ''
40
-
41
- meth << "desc #{name.inspect}, #{comment.inspect}\n" if comment
42
- meth << "def #{name}\n"
43
-
44
- meth << prereqs.map do |pre|
45
- pre = pre.to_s
46
- pre = file_task_name(pre) if Rake::Task[pre].is_a?(Rake::FileTask)
47
- ' ' + pre
48
- end.join("\n")
49
-
50
- meth << "\n\n" unless prereqs.empty? || actions.empty?
51
-
52
- meth << actions.map do |act|
53
- act = act.to_ruby
54
- unless act.gsub!(/^proc \{ \|(\w+)\|\n/,
55
- " \\1 = Struct.new(:name).new(#{name.inspect}) # A crude mock Rake::Task object\n")
56
- act.gsub!(/^proc \{\n/, '')
57
- end
58
- act.gsub(/\n\}$/, '')
59
- end.join("\n")
60
-
61
- meth << "\nend"
62
-
63
- if file_task
64
- @private_methods << meth
65
- return
66
- end
67
-
68
- meth
69
- end
70
-
71
- body = Rake::Task.tasks.map(&method(:method_for_task)).compact.map { |meth| meth.gsub(/^/, ' ') }.join("\n\n")
72
-
73
- unless @private_methods.empty?
74
- body << "\n\n private\n\n"
75
- body << @private_methods.map { |meth| meth.gsub(/^/, ' ') }.join("\n\n")
76
- end
77
-
78
- requires = $requires.map { |r| "require #{r.inspect}" }.join("\n")
79
-
80
- File.open(output, 'w') { |f| f.write(<<END.lstrip) }
81
- #{requires}
82
-
83
- class Default < Thor
84
- #{body}
85
- end
86
- END
File without changes
@@ -1,9 +0,0 @@
1
- class File #:nodoc:
2
-
3
- unless File.respond_to?(:binread)
4
- def self.binread(file)
5
- File.open(file, 'rb') { |f| f.read }
6
- end
7
- end
8
-
9
- end
@@ -1,100 +0,0 @@
1
- class Thor
2
- module CoreExt #:nodoc:
3
-
4
- if RUBY_VERSION >= '1.9'
5
- class OrderedHash < ::Hash
6
- end
7
- else
8
- # This class is based on the Ruby 1.9 ordered hashes.
9
- #
10
- # It keeps the semantics and most of the efficiency of normal hashes
11
- # while also keeping track of the order in which elements were set.
12
- #
13
- class OrderedHash #:nodoc:
14
- include Enumerable
15
-
16
- Node = Struct.new(:key, :value, :next, :prev)
17
-
18
- def initialize
19
- @hash = {}
20
- end
21
-
22
- def [](key)
23
- @hash[key] && @hash[key].value
24
- end
25
-
26
- def []=(key, value)
27
- if node = @hash[key]
28
- node.value = value
29
- else
30
- node = Node.new(key, value)
31
-
32
- if @first.nil?
33
- @first = @last = node
34
- else
35
- node.prev = @last
36
- @last.next = node
37
- @last = node
38
- end
39
- end
40
-
41
- @hash[key] = node
42
- value
43
- end
44
-
45
- def delete(key)
46
- if node = @hash[key]
47
- prev_node = node.prev
48
- next_node = node.next
49
-
50
- next_node.prev = prev_node if next_node
51
- prev_node.next = next_node if prev_node
52
-
53
- @first = next_node if @first == node
54
- @last = prev_node if @last == node
55
-
56
- value = node.value
57
- end
58
-
59
- @hash.delete(key)
60
- value
61
- end
62
-
63
- def keys
64
- self.map { |k, v| k }
65
- end
66
-
67
- def values
68
- self.map { |k, v| v }
69
- end
70
-
71
- def each
72
- return unless @first
73
- yield [@first.key, @first.value]
74
- node = @first
75
- yield [node.key, node.value] while node = node.next
76
- self
77
- end
78
-
79
- def merge(other)
80
- hash = self.class.new
81
-
82
- self.each do |key, value|
83
- hash[key] = value
84
- end
85
-
86
- other.each do |key, value|
87
- hash[key] = value
88
- end
89
-
90
- hash
91
- end
92
-
93
- def empty?
94
- @hash.empty?
95
- end
96
- end
97
- end
98
-
99
- end
100
- end
data/lib/thor/task.rb DELETED
@@ -1,132 +0,0 @@
1
- class Thor
2
- class Task < Struct.new(:name, :description, :long_description, :usage, :options)
3
- FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
4
-
5
- def initialize(name, description, long_description, usage, options=nil)
6
- super(name.to_s, description, long_description, usage, options || {})
7
- end
8
-
9
- def initialize_copy(other) #:nodoc:
10
- super(other)
11
- self.options = other.options.dup if other.options
12
- end
13
-
14
- def hidden?
15
- false
16
- end
17
-
18
- # By default, a task invokes a method in the thor class. You can change this
19
- # implementation to create custom tasks.
20
- def run(instance, args=[])
21
- arity = nil
22
-
23
- if private_method?(instance)
24
- instance.class.handle_no_task_error(name)
25
- elsif public_method?(instance)
26
- arity = instance.method(name).arity
27
- instance.send(name, *args)
28
- elsif local_method?(instance, :method_missing)
29
- instance.send(:method_missing, name.to_sym, *args)
30
- else
31
- instance.class.handle_no_task_error(name)
32
- end
33
- rescue ArgumentError => e
34
- handle_argument_error?(instance, e, caller) ?
35
- instance.class.handle_argument_error(self, e, arity) : (raise e)
36
- rescue NoMethodError => e
37
- handle_no_method_error?(instance, e, caller) ?
38
- instance.class.handle_no_task_error(name) : (raise e)
39
- end
40
-
41
- # Returns the formatted usage by injecting given required arguments
42
- # and required options into the given usage.
43
- def formatted_usage(klass, namespace = true, subcommand = false)
44
- if namespace
45
- namespace = klass.namespace
46
- formatted = "#{namespace.gsub(/^(default)/,'')}:"
47
- end
48
- formatted = "#{klass.namespace.split(':').last} " if subcommand
49
-
50
- formatted ||= ""
51
-
52
- # Add usage with required arguments
53
- formatted << if klass && !klass.arguments.empty?
54
- usage.to_s.gsub(/^#{name}/) do |match|
55
- match << " " << klass.arguments.map{ |a| a.usage }.compact.join(' ')
56
- end
57
- else
58
- usage.to_s
59
- end
60
-
61
- # Add required options
62
- formatted << " #{required_options}"
63
-
64
- # Strip and go!
65
- formatted.strip
66
- end
67
-
68
- protected
69
-
70
- def not_debugging?(instance)
71
- !(instance.class.respond_to?(:debugging) && instance.class.debugging)
72
- end
73
-
74
- def required_options
75
- @required_options ||= options.map{ |_, o| o.usage if o.required? }.compact.sort.join(" ")
76
- end
77
-
78
- # Given a target, checks if this class name is a public method.
79
- def public_method?(instance) #:nodoc:
80
- !(instance.public_methods & [name.to_s, name.to_sym]).empty?
81
- end
82
-
83
- def private_method?(instance)
84
- !(instance.private_methods & [name.to_s, name.to_sym]).empty?
85
- end
86
-
87
- def local_method?(instance, name)
88
- methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false)
89
- !(methods & [name.to_s, name.to_sym]).empty?
90
- end
91
-
92
- def sans_backtrace(backtrace, caller) #:nodoc:
93
- saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) }
94
- saned -= caller
95
- end
96
-
97
- def handle_argument_error?(instance, error, caller)
98
- not_debugging?(instance) && error.message =~ /wrong number of arguments/ && begin
99
- saned = sans_backtrace(error.backtrace, caller)
100
- # Ruby 1.9 always include the called method in the backtrace
101
- saned.empty? || (saned.size == 1 && RUBY_VERSION >= "1.9")
102
- end
103
- end
104
-
105
- def handle_no_method_error?(instance, error, caller)
106
- not_debugging?(instance) &&
107
- error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
108
- end
109
- end
110
-
111
- # A task that is hidden in help messages but still invocable.
112
- class HiddenTask < Task
113
- def hidden?
114
- true
115
- end
116
- end
117
-
118
- # A dynamic task that handles method missing scenarios.
119
- class DynamicTask < Task
120
- def initialize(name, options=nil)
121
- super(name.to_s, "A dynamically-generated task", name.to_s, name.to_s, options)
122
- end
123
-
124
- def run(instance, args=[])
125
- if (instance.methods & [name.to_s, name.to_sym]).empty?
126
- super
127
- else
128
- instance.class.handle_no_task_error(name)
129
- end
130
- end
131
- end
132
- end
@@ -1,170 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
- require 'thor/actions'
3
-
4
- describe Thor::Actions::CreateFile do
5
- before do
6
- ::FileUtils.rm_rf(destination_root)
7
- end
8
-
9
- def create_file(destination=nil, config={}, options={})
10
- @base = MyCounter.new([1,2], options, { :destination_root => destination_root })
11
- @base.stub!(:file_name).and_return('rdoc')
12
-
13
- @action = Thor::Actions::CreateFile.new(@base, destination, "CONFIGURATION",
14
- { :verbose => !@silence }.merge(config))
15
- end
16
-
17
- def invoke!
18
- capture(:stdout){ @action.invoke! }
19
- end
20
-
21
- def revoke!
22
- capture(:stdout){ @action.revoke! }
23
- end
24
-
25
- def silence!
26
- @silence = true
27
- end
28
-
29
- describe "#invoke!" do
30
- it "creates a file" do
31
- create_file("doc/config.rb")
32
- invoke!
33
- File.exists?(File.join(destination_root, "doc/config.rb")).should be_true
34
- end
35
-
36
- it "does not create a file if pretending" do
37
- create_file("doc/config.rb", {}, :pretend => true)
38
- invoke!
39
- File.exists?(File.join(destination_root, "doc/config.rb")).should be_false
40
- end
41
-
42
- it "shows created status to the user" do
43
- create_file("doc/config.rb")
44
- invoke!.should == " create doc/config.rb\n"
45
- end
46
-
47
- it "does not show any information if log status is false" do
48
- silence!
49
- create_file("doc/config.rb")
50
- invoke!.should be_empty
51
- end
52
-
53
- it "returns the given destination" do
54
- capture(:stdout) do
55
- create_file("doc/config.rb").invoke!.should == "doc/config.rb"
56
- end
57
- end
58
-
59
- it "converts encoded instructions" do
60
- create_file("doc/%file_name%.rb.tt")
61
- invoke!
62
- File.exists?(File.join(destination_root, "doc/rdoc.rb.tt")).should be_true
63
- end
64
-
65
- describe "when file exists" do
66
- before do
67
- create_file("doc/config.rb")
68
- invoke!
69
- end
70
-
71
- describe "and is identical" do
72
- it "shows identical status" do
73
- create_file("doc/config.rb")
74
- invoke!
75
- invoke!.should == " identical doc/config.rb\n"
76
- end
77
- end
78
-
79
- describe "and is not identical" do
80
- before do
81
- File.open(File.join(destination_root, 'doc/config.rb'), 'w'){ |f| f.write("FOO = 3") }
82
- end
83
-
84
- it "shows forced status to the user if force is given" do
85
- create_file("doc/config.rb", {}, :force => true).should_not be_identical
86
- invoke!.should == " force doc/config.rb\n"
87
- end
88
-
89
- it "shows skipped status to the user if skip is given" do
90
- create_file("doc/config.rb", {}, :skip => true).should_not be_identical
91
- invoke!.should == " skip doc/config.rb\n"
92
- end
93
-
94
- it "shows forced status to the user if force is configured" do
95
- create_file("doc/config.rb", :force => true).should_not be_identical
96
- invoke!.should == " force doc/config.rb\n"
97
- end
98
-
99
- it "shows skipped status to the user if skip is configured" do
100
- create_file("doc/config.rb", :skip => true).should_not be_identical
101
- invoke!.should == " skip doc/config.rb\n"
102
- end
103
-
104
- it "shows conflict status to ther user" do
105
- create_file("doc/config.rb").should_not be_identical
106
- $stdin.should_receive(:gets).and_return('s')
107
- file = File.join(destination_root, 'doc/config.rb')
108
-
109
- content = invoke!
110
- content.should =~ /conflict doc\/config\.rb/
111
- content.should =~ /Overwrite #{file}\? \(enter "h" for help\) \[Ynaqdh\]/
112
- content.should =~ /skip doc\/config\.rb/
113
- end
114
-
115
- it "creates the file if the file collision menu returns true" do
116
- create_file("doc/config.rb")
117
- $stdin.should_receive(:gets).and_return('y')
118
- invoke!.should =~ /force doc\/config\.rb/
119
- end
120
-
121
- it "skips the file if the file collision menu returns false" do
122
- create_file("doc/config.rb")
123
- $stdin.should_receive(:gets).and_return('n')
124
- invoke!.should =~ /skip doc\/config\.rb/
125
- end
126
-
127
- it "executes the block given to show file content" do
128
- create_file("doc/config.rb")
129
- $stdin.should_receive(:gets).and_return('d')
130
- $stdin.should_receive(:gets).and_return('n')
131
- @base.shell.should_receive(:system).with(/diff -u/)
132
- invoke!
133
- end
134
- end
135
- end
136
- end
137
-
138
- describe "#revoke!" do
139
- it "removes the destination file" do
140
- create_file("doc/config.rb")
141
- invoke!
142
- revoke!
143
- File.exists?(@action.destination).should be_false
144
- end
145
-
146
- it "does not raise an error if the file does not exist" do
147
- create_file("doc/config.rb")
148
- revoke!
149
- File.exists?(@action.destination).should be_false
150
- end
151
- end
152
-
153
- describe "#exists?" do
154
- it "returns true if the destination file exists" do
155
- create_file("doc/config.rb")
156
- @action.exists?.should be_false
157
- invoke!
158
- @action.exists?.should be_true
159
- end
160
- end
161
-
162
- describe "#identical?" do
163
- it "returns true if the destination file and is identical" do
164
- create_file("doc/config.rb")
165
- @action.identical?.should be_false
166
- invoke!
167
- @action.identical?.should be_true
168
- end
169
- end
170
- end
@@ -1,81 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
- require 'thor/actions'
3
- require 'tempfile'
4
-
5
- describe Thor::Actions::CreateLink do
6
- before do
7
- @hardlink_to = File.join(Dir.tmpdir, 'linkdest.rb')
8
- ::FileUtils.rm_rf(destination_root)
9
- ::FileUtils.rm_rf(@hardlink_to)
10
- end
11
-
12
- def create_link(destination=nil, config={}, options={})
13
- @base = MyCounter.new([1,2], options, { :destination_root => destination_root })
14
- @base.stub!(:file_name).and_return('rdoc')
15
-
16
- @tempfile = Tempfile.new("config.rb")
17
-
18
- @action = Thor::Actions::CreateLink.new(@base, destination, @tempfile.path,
19
- { :verbose => !@silence }.merge(config))
20
- end
21
-
22
- def invoke!
23
- capture(:stdout){ @action.invoke! }
24
- end
25
-
26
- def silence!
27
- @silence = true
28
- end
29
-
30
- describe "#invoke!" do
31
- it "creates a symbolic link for :symbolic => true" do
32
- create_link("doc/config.rb", :symbolic => true)
33
- invoke!
34
- destination_path = File.join(destination_root, "doc/config.rb")
35
- File.exists?(destination_path).should be_true
36
- File.symlink?(destination_path).should be_true
37
- end
38
-
39
- it "creates a hard link for :symbolic => false" do
40
- create_link(@hardlink_to, :symbolic => false)
41
- invoke!
42
- destination_path = @hardlink_to
43
- File.exists?(destination_path).should be_true
44
- File.symlink?(destination_path).should be_false
45
- end
46
-
47
- it "creates a symbolic link by default" do
48
- create_link("doc/config.rb")
49
- invoke!
50
- destination_path = File.join(destination_root, "doc/config.rb")
51
- File.exists?(destination_path).should be_true
52
- File.symlink?(destination_path).should be_true
53
- end
54
-
55
- it "does not create a link if pretending" do
56
- create_link("doc/config.rb", {}, :pretend => true)
57
- invoke!
58
- File.exists?(File.join(destination_root, "doc/config.rb")).should be_false
59
- end
60
-
61
- it "shows created status to the user" do
62
- create_link("doc/config.rb")
63
- invoke!.should == " create doc/config.rb\n"
64
- end
65
-
66
- it "does not show any information if log status is false" do
67
- silence!
68
- create_link("doc/config.rb")
69
- invoke!.should be_empty
70
- end
71
- end
72
-
73
- describe "#identical?" do
74
- it "returns true if the destination link exists and is identical" do
75
- create_link("doc/config.rb")
76
- @action.identical?.should be_false
77
- invoke!
78
- @action.identical?.should be_true
79
- end
80
- end
81
- end