There are some great helper methods from Thor::Actions (http://textmate.rubyforge.org/thor/Thor/Actions.html) that I want access to but I cannot seem to use them without employing a Thor CLI app.
I've tried simply:
require "rubygems"
require "thor"
Thor::Actions.create_file "foo.txt", "contents"
Which throws:
run.rb:4:in '<main>': undefined method 'create_file' for Thor::Actions:Module (NoMethodError)
I realize I might be missing something really simple here. Thanks.
Thor intends for your classes to subclass the Thor class. The Thor class then includes and extends modules allowing their methods to be class methods. If you look at the source, for example Actions.rb
, you will see what I mean:
# thor/lib/thor/actions.rb
class Thor
module Actions
# this is the interesting part and answers your question
def self.included(base) #:nodoc:
base.extend ClassMethods
end
module ClassMethods
This is a common Ruby idiom that uses a mixin to define class methods (as opposed to instance methods) on its inclusor.
As an example,
[2] pry(main)> class Klass
[2] pry(main)* module Mod
[2] pry(main)* def self.included(base)
[2] pry(main)* base.extend ClassMethods
[2] pry(main)* end
[2] pry(main)* module ClassMethods
[2] pry(main)* def act_as_class_method
[2] pry(main)* puts "Im a class method now!!!"
[2] pry(main)* end
[2] pry(main)* end
[2] pry(main)* end
[2] pry(main)* end
=> nil
Now calling
Klass::Mod.act_as_class_method
results in the same error you had
NoMethodError: undefined method `act_as_class_method' for Klass::Mod:Module
from (pry):26:in `__pry__'
But if you subclass Klass
and include Klass::Mod
the included
call back extends
the ClassMethod
module, letting you use the methods defined in ClassMethods
as class methods
[4] pry(main)> class Example < Klass
[4] pry(main)* include Klass::Mod
[4] pry(main)* self.act_as_class_method
[4] pry(main)* end
=> Im a class method now!!!
=> nil
This took me a while to figure out at first, so don't feel bad and no, its not that simple or obvious.
To use Thor::Actions
without inheriting from Thor
:
class Builder # or whatever
# To get your hands on the `from_superclass` method
include Thor::Base
# What we're interested in…
include Thor::Actions
source_root "/path/to/where/things/come/out"
def initialize(*)
# whatever you might want to do
@destination_stack = [self.class.source_root]
end
end
Hope someone else finds this useful. Tried and tested with Thor v0.18.1; as this is internal API stuff it's likely to break at some point in the future.
You can then use the helper methods in your Builder
class like so:
class Builder
def build
in_root { 'do things' }
create_file 'etc'
end
end
Edit: If you want to control where you create files and folders you need to set destination_root
like so:
class Builder
include Thor::Base
include Thor::Actions
source_root Dir.pwd
def initialize(root)
self.destination_root = File.expand_path(root)
end
def build
directory 'templates', 'target'
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With