I know I can open a class like String
and add functionality. This test script camelize.rb
works pretty well.
#!/usr/bin/env ruby
class String
def camelize
self.split("_").map(&:capitalize).join
end
end
class Test
def test
p "test_me".camelize
end
end
Test.test
Prints "TestMe"
However inside a thor file this doesn't work. E.g. test.thor
p "TEST ONE"
class String
p "TEST TWO"
def camelize
self.split("_").map(&:capitalize).join
end
end
class Test < Thor
p "TEST THREE"
desc "camel", "A test"
def camel
p "test_me".camelize
end
end
Installing it via thor install test.thor
, running
$ thor test:camel
"TEST ONE"
"TEST TWO"
"TEST THREE"
/Users/Kassi/.thor/ba3ea78d7f807c4c13ec6b61286788b5:13:in `camel': undefined method `camelize' for "test_me":String (NoMethodError)
Why and how to fix it?
The problem is here:
Thor::Sandbox.class_eval(content, path)
So what it does is take your file and load it inside of an empty module, thus namespacing it (not sure if qualifies as "sandboxing").
class Thor
module Sandbox
end
end
So, your attempt at reopening the String
actually creates a new class Thor::Sandbox::String
which no one knows about. String literals continue to create instances of String
.
Open the top-level string instead of creating a nested one.
class ::String
def camelize
self.split("_").map(&:capitalize).join
end
end
Thor actually already includes method for camelizing strings, Thor::Util.camel_case
:
def camel_case(str)
return str if str !~ /_/ && str =~ /[A-Z]+.*/
str.split("_").map { |i| i.capitalize }.join
end