Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Migration to rspec mock framework.

  • Loading branch information...
commit 7f892ff82d73723377e5d82b5c0d2228e8489721 1 parent 983643e
@josevalim josevalim authored
View
16 lib/thor.rb
@@ -160,7 +160,7 @@ def help(shell, options={})
class_options_help(shell, nil => task.options.map { |_, o| o })
shell.say task.description
else
- list = printable_tasks(!options[:short])
+ list = printable_tasks
Thor::Util.thor_classes_in(self).each do |klass|
list += klass.printable_tasks(false)
@@ -168,14 +168,10 @@ def help(shell, options={})
list.sort!{ |a,b| a[0] <=> b[0] }
- if options[:short]
- shell.print_table(list, :truncate => true)
- else
- shell.say "Tasks:"
- shell.print_table(list, :ident => 2, :truncate => true)
- shell.say
- class_options_help(shell)
- end
+ shell.say "Tasks:"
+ shell.print_table(list, :ident => 2, :truncate => true)
+ shell.say
+ class_options_help(shell)
end
end
@@ -183,7 +179,7 @@ def printable_tasks(all=true)
(all ? all_tasks : tasks).map do |_, task|
item = []
item << banner(task)
- item << "# #{task.description}" if task.description
+ item << (task.description ? "# #{task.description.gsub(/\s+/m,' ')}" : "")
item
end
end
View
29 lib/thor/group.rb
@@ -42,15 +42,11 @@ def start(given_args=ARGV, config={})
# short:: When true, shows only usage.
#
def help(shell, options={})
- if options[:short]
- shell.say banner
- else
- shell.say "Usage:"
- shell.say " #{banner}\n"
- shell.say ""
- class_options_help(shell)
- shell.say self.desc if self.desc
- end
+ shell.say "Usage:"
+ shell.say " #{banner}\n"
+ shell.say
+ class_options_help(shell)
+ shell.say self.desc if self.desc
end
# Stores invocations for this class merging with superclass values.
@@ -214,13 +210,25 @@ def get_options_from_invocations(group_options, base_options) #:nodoc:
end
end
+ def printable_tasks(*)
+ item = []
+ item << banner
+ item << (desc ? "# #{desc.gsub(/\s+/m,' ')}" : "")
+ [item]
+ end
+
protected
# The banner for this class. You can customize it if you are invoking the
# thor class by another ways which is not the Thor::Runner.
#
def banner
- "thor #{self.namespace} #{self.arguments.map {|a| a.usage }.join(' ')}"
+ "thor #{self_task.formatted_usage(self, false)}"
+ end
+
+ # Represents the whole class as a task.
+ def self_task #:nodoc:
+ Thor::Task::Dynamic.new(self.namespace, class_options)
end
def baseclass #:nodoc:
@@ -239,7 +247,6 @@ def create_task(meth) #:nodoc:
# Shortcut to invoke with padding and block handling. Use internally by
# invoke and invoke_from_option class methods.
- #
def _invoke_for_class_method(klass, task=nil, *args, &block) #:nodoc:
shell.padding += 1
View
82 lib/thor/runner.rb
@@ -124,11 +124,7 @@ def update(name)
method_options :internal => :boolean
def installed
initialize_thorfiles(nil, true)
-
- klasses = Thor::Base.subclasses
- klasses -= [Thor, Thor::Runner] unless options["internal"]
-
- display_klasses(true, klasses)
+ display_klasses(true, options["internal"])
end
desc "list [SEARCH]", "List the available thor tasks (--substring means .*SEARCH)"
@@ -144,7 +140,7 @@ def list(search="")
(options[:all] || k.group == group) && k.namespace =~ search
end
- display_klasses(false, klasses)
+ display_klasses(false, false, klasses)
end
private
@@ -160,7 +156,7 @@ def thor_root
def thor_yaml
@thor_yaml ||= begin
yaml_file = File.join(thor_root, "thor.yml")
- yaml = YAML.load_file(yaml_file) if File.exists?(yaml_file)
+ yaml = YAML.load_file(yaml_file) if File.exists?(yaml_file)
yaml || {}
end
end
@@ -219,9 +215,6 @@ def initialize_thorfiles(relevant_to=nil, skip_lookup=false)
# 5. c:\ <-- no Thorfiles found!
#
def thorfiles(relevant_to=nil, skip_lookup=false)
- # TODO Remove this dealing with deprecated thor when :namespaces: is available as constants
- save_yaml(thor_yaml) if Thor::Util.convert_constants_to_namespaces(thor_yaml)
-
thorfiles = []
unless skip_lookup
@@ -257,47 +250,54 @@ def thorfiles_relevant_to(meth)
# Display information about the given klasses. If with_module is given,
# it shows a table with information extracted from the yaml file.
#
- def display_klasses(with_modules=false, klasses=Thor.subclasses)
- klasses -= [Thor, Thor::Runner] unless with_modules
- raise Error, "No Thor tasks available" if klasses.empty?
+ def display_klasses(with_modules=false, show_internal=false, klasses=Thor::Base.subclasses)
+ klasses -= [Thor, Thor::Runner, Thor::Group] unless show_internal
- if with_modules && !thor_yaml.empty?
- info = []
- labels = ["Modules", "Namespaces"]
+ raise Error, "No Thor tasks available" if klasses.empty?
+ show_modules if with_modules && !thor_yaml.empty?
- info << labels
- info << [ "-" * labels[0].size, "-" * labels[1].size ]
+ # Remove subclasses
+ klasses.dup.each do |klass|
+ klasses -= Thor::Util.thor_classes_in(klass)
+ end
- thor_yaml.each do |name, hash|
- info << [ name, hash[:namespaces].join(", ") ]
- end
+ list = Hash.new { |h,k| h[k] = [] }
+ groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
- print_table info
- say ""
- end
+ # Get classes which inherit from Thor
+ (klasses - groups).each { |k| list[k.namespace] += k.printable_tasks(false) }
- unless klasses.empty?
- klasses.dup.each do |klass|
- klasses -= Thor::Util.thor_classes_in(klass)
- end
+ # Get classes which inherit from Thor::Base
+ groups.map! { |k| k.printable_tasks(false).first }
+ list["root"] = groups
- klasses.each { |k| display_tasks(k) }
- else
- say "\033[1;34mNo Thor tasks available\033[0m"
- end
+ # Order namespaces with default coming first
+ list = list.sort{ |a,b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
+ list.each { |n, tasks| display_tasks(n, tasks) unless tasks.empty? }
end
- # Display tasks from the given Thor class.
- #
- def display_tasks(klass)
- unless klass.tasks.empty?
- base = klass.namespace
+ def display_tasks(namespace, list) #:nodoc:
+ list.sort!{ |a,b| a[0] <=> b[0] }
- say shell.set_color(base, :blue, true)
- say "-" * base.length
+ say shell.set_color(namespace, :blue, true)
+ say "-" * namespace.size
+
+ print_table(list, :truncate => true)
+ say
+ end
- klass.help(shell, :short => true)
- say
+ def show_modules #:nodoc:
+ info = []
+ labels = ["Modules", "Namespaces"]
+
+ info << labels
+ info << [ "-" * labels[0].size, "-" * labels[1].size ]
+
+ thor_yaml.each do |name, hash|
+ info << [ name, hash[:namespaces].join(", ") ]
end
+
+ print_table info
+ say ""
end
end
View
4 lib/thor/task.rb
@@ -4,8 +4,8 @@ class Task < Struct.new(:name, :description, :usage, :options)
# A dynamic task that handles method missing scenarios.
class Dynamic < Task
- def initialize(name)
- super(name.to_s, "A dynamically-generated task", name.to_s)
+ def initialize(name, options=nil)
+ super(name.to_s, "A dynamically-generated task", name.to_s, options)
end
def run(instance, args=[])
View
20 lib/thor/util.rb
@@ -165,26 +165,6 @@ def self.load_thorfile(path, content=nil)
end
end
- # Receives a yaml (hash) and updates all constants entries to namespace.
- # This was added to deal with deprecated versions of Thor.
- #
- # TODO Deprecate this method in the future.
- #
- # ==== Returns
- # TrueClass|FalseClass:: Returns true if any change to the yaml file was made.
- #
- def self.convert_constants_to_namespaces(yaml)
- yaml_changed = false
-
- yaml.each do |k, v|
- next unless v[:constants] && v[:namespaces].nil?
- yaml_changed = true
- yaml[k][:namespaces] = v[:constants].map{|c| Thor::Util.namespace_from_thor_class(c)}
- end
-
- yaml_changed
- end
-
def self.user_home
@@user_home ||= if ENV["HOME"]
ENV["HOME"]
View
64 spec/runner_spec.rb
@@ -26,11 +26,11 @@
it "shows information about a specific Thor group class" do
content = capture(:stdout){ Thor::Runner.start(["help", "my_counter"]) }
- content.must =~ /my_counter N \[N\]/
+ content.must =~ /my_counter N/
end
it "raises error if a class/task cannot be found" do
- mock(Thor::Runner).exit(1){ }
+ Thor::Runner.should_receive(:exit).with(1)
content = capture(:stderr){ Thor::Runner.start(["help", "unknown"]) }
content.must =~ /could not find Thor class or task 'unknown'/
end
@@ -39,7 +39,7 @@
describe "#start" do
it "invokes a task from Thor::Runner" do
ARGV.replace ["list"]
- capture(:stdout){ Thor::Runner.start }.must =~ /my_counter N \[N\]/
+ capture(:stdout){ Thor::Runner.start }.must =~ /my_counter N/
end
it "invokes a task from a specific Thor class" do
@@ -68,7 +68,7 @@
end
it "raises an error if class/task can't be found" do
- mock(Thor::Runner).exit(1){ }
+ Thor::Runner.should_receive(:exit).with(1)
ARGV.replace ["unknown"]
capture(:stderr){ Thor::Runner.start }.must =~ /could not find Thor class or task 'unknown'/
end
@@ -96,14 +96,16 @@
"random" => {
:location => @location,
:filename => "4a33b894ffce85d7b412fc1b36f88fe0",
- :constants => ["Amazing"]
+ :namespaces => ["amazing"]
}
}
+ root_file = File.join(Thor::Util.thor_root, "thor.yml")
+
# Stub load and save to avoid thor.yaml from being overwritten
- stub(YAML).load_file { @original_yaml }
- stub(File).exists?(File.join(Thor::Util.thor_root, "thor.yml")){ true }
- stub(File).open(File.join(Thor::Util.thor_root, "thor.yml"), "w")
+ YAML.stub!(:load_file).and_return(@original_yaml)
+ File.stub!(:exists?).with(root_file).and_return(true)
+ File.stub!(:open).with(root_file, "w")
end
describe "list" do
@@ -115,7 +117,7 @@
it "gives a list of the available Thor::Group classes" do
ARGV.replace ["list"]
- capture(:stdout) { Thor::Runner.start }.must =~ /my_counter N \[N\]/
+ capture(:stdout) { Thor::Runner.start }.must =~ /my_counter N/
end
it "can filter a list of the available tasks by --group" do
@@ -148,26 +150,12 @@
ARGV.replace [":test"]
capture(:stdout) { Thor::Runner.start }.must == "test\n"
end
-
- it "updates the yaml file when invoked" do
- capture(:stdout) { Thor::Runner.start(["list"]) }
- @original_yaml["random"][:namespaces].must == ["amazing"]
- end
- end
-
- describe "update" do
- it "updates existing thor files" do
- mock.instance_of(Thor::Runner).install(@original_yaml["random"][:location]) { true }
- stub(File).delete(File.join(Thor::Util.thor_root, @original_yaml["random"][:filename]))
- silence(:stdout) { Thor::Runner.start(["update", "random"]) }
- end
end
describe "uninstall" do
before(:each) do
- stub.instance_of(Thor::Runner).save_yaml(anything)
- stub(File).delete(anything)
- stub(@original_yaml).delete(anything)
+ path = File.join(Thor::Util.thor_root, @original_yaml["random"][:filename])
+ FileUtils.should_receive(:rm_rf).with(path)
end
it "uninstalls existing thor modules" do
@@ -177,7 +165,7 @@
describe "installed" do
before(:each) do
- stub(Dir).[](anything) { [] }
+ Dir.should_receive(:[]).and_return([])
end
it "displays the modules installed in a pretty way" do
@@ -187,16 +175,24 @@
end
end
- describe "install" do
- it "installs thor files" do
- ARGV.replace ["install", @location]
+ describe "install/update" do
+ before(:each) do
+ FileUtils.stub!(:mkdir_p)
+ FileUtils.stub!(:touch)
+ $stdin.stub!(:gets).and_return("Y")
- # Stubs for the file system interactions
- stub.instance_of(Thor::Base.shell).no? { false }
- stub(FileUtils).mkdir_p
- stub(FileUtils).touch
+ path = File.join(Thor::Util.thor_root, Digest::MD5.hexdigest(@location + "random"))
+ File.should_receive(:open).with(path, "w")
+ end
- mock(File).open(File.join(Thor::Util.thor_root, Digest::MD5.hexdigest(@location + "random")), "w")
+ it "updates existing thor files" do
+ path = File.join(Thor::Util.thor_root, @original_yaml["random"][:filename])
+ File.should_receive(:delete).with(path)
+ silence(:stdout) { Thor::Runner.start(["update", "random"]) }
+ end
+
+ it "installs thor files" do
+ ARGV.replace ["install", @location]
silence(:stdout) { Thor::Runner.start }
end
end
View
3  spec/spec_helper.rb
@@ -6,6 +6,7 @@
require 'rubygems'
require 'rr'
+require 'rdoc'
require 'diff/lcs' # You need diff/lcs installed to run specs (but not to run Thor).
# Load fixtures
@@ -25,8 +26,6 @@
end
Spec::Runner.configure do |config|
- config.mock_with :rr
-
def capture(stream)
begin
stream = stream.to_s
View
24 spec/util_spec.rb
@@ -169,28 +169,4 @@ def self.clear_user_home!
Thor::Util.user_home.must == "/home/user/"
end
end
-
- describe "#convert_constants_to_namespaces" do
- before(:each) do
- @hash = {
- :git => {
- :constants => [Object, "Thor::Sandbox::Package", Thor::CoreExt::OrderedHash]
- }
- }
- end
-
- it "converts constants in the hash to namespaces" do
- Thor::Util.convert_constants_to_namespaces(@hash)
- @hash[:git][:namespaces].must == [ "object", "package", "thor:core_ext:ordered_hash" ]
- end
-
- it "returns true if the hash changed" do
- Thor::Util.convert_constants_to_namespaces(@hash).must be_true
- end
-
- it "does not add namespaces to the hash if namespaces were already added" do
- Thor::Util.convert_constants_to_namespaces(@hash)
- Thor::Util.convert_constants_to_namespaces(@hash).must be_false
- end
- end
end
Please sign in to comment.
Something went wrong with that request. Please try again.