# module Bundler::Thor::Util

This module holds several utilities:

1) Methods to convert thor namespaces to constants and vice-versa.

    Bundler::Thor::Util.namespace_from_thor_class(Foo::Bar::Baz) #=> "foo:bar:baz"

2) Loading thor files and sandboxing:

    Bundler::Thor::Util.load_thorfile("~/.thor/foo")

### Public Class Methods

camel_case(str) click to toggle source

Receives a string and convert it to camel case. `camel_case` returns CamelCase.

#### Parameters¶ ↑

`String`

#### Returns¶ ↑

`String`

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 104
    def camel_case(str)
      return str if str !~ /_/ && str =~ /[A-Z]+.*/
      str.split("_").map(&:capitalize).join
    end

escape_globs(path) click to toggle source

Returns a string that has had any glob characters escaped. The glob characters are `* ? { } [ ]`.

#### Examples¶ ↑

    Bundler::Thor::Util.escape_globs('[apps]')   # => '\[apps\]'

#### Parameters¶ ↑

`String`

#### Returns¶ ↑

`String`

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 263
    def escape_globs(path)
      path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&')
    end

find_by_namespace(namespace) click to toggle source

Receives a namespace and search for it in the `Bundler::Thor::Base` subclasses.

#### Parameters¶ ↑

namespace<String>

  The namespace to search for.

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 24
    def find_by_namespace(namespace)
      namespace = "default#{namespace}" if namespace.empty? || namespace =~ /^:/
      Bundler::Thor::Base.subclasses.detect { |klass| klass.namespace == namespace }
    end

find_class_and_command_by_namespace(namespace, fallback = true) click to toggle source

Receives a namespace and tries to retrieve a Bundler::Thor or `Bundler::Thor::Group` class from it. It first searches for a class using the all the given namespace, if it's not found, removes the highest entry and searches for the class again. If found, returns the highest entry as the class name.

#### Examples¶ ↑

    class Foo::Bar < Bundler::Thor
      def baz
      end
    end

    class Baz::Foo < Bundler::Thor::Group
    end

    Bundler::Thor::Util.namespace_to_thor_class("foo:bar")     #=> Foo::Bar, nil # will invoke default command
    Bundler::Thor::Util.namespace_to_thor_class("baz:foo")     #=> Baz::Foo, nil
    Bundler::Thor::Util.namespace_to_thor_class("foo:bar:baz") #=> Foo::Bar, "baz"

#### Parameters¶ ↑

namespace<String>

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 131
    def find_class_and_command_by_namespace(namespace, fallback = true)
      if namespace.include?(":") # look for a namespaced command
        pieces  = namespace.split(":")
        command = pieces.pop
        klass   = Bundler::Thor::Util.find_by_namespace(pieces.join(":"))
      end
      unless klass # look for a Bundler::Thor::Group with the right name
        klass = Bundler::Thor::Util.find_by_namespace(namespace)
        command = nil
      end
      if !klass && fallback # try a command in the default namespace
        command = namespace
        klass   = Bundler::Thor::Util.find_by_namespace("")
      end
      [klass, command]
    end

Also aliased as: find_class_and_task_by_namespace
find_class_and_task_by_namespace(namespace, fallback = true)
Alias for: find_class_and_command_by_namespace
globs_for(path) click to toggle source

Where to look for Bundler::Thor files.

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 212
    def globs_for(path)
      path = escape_globs(path)
      ["#{path}/Bundler::Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
    end

load_thorfile(path, content = nil, debug = false) click to toggle source

Receives a path and load the thor file in the path. The file is evaluated inside the sandbox to avoid namespacing conflicts.

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 152
    def load_thorfile(path, content = nil, debug = false)
      content ||= File.binread(path)

      begin
        Bundler::Thor::Sandbox.class_eval(content, path)
      rescue StandardError => e
        $stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}")
        if debug
          $stderr.puts(*e.backtrace)
        else
          $stderr.puts(e.backtrace.first)
        end
      end
    end

namespace_from_thor_class(constant) click to toggle source

Receives a constant and converts it to a Bundler::Thor namespace. Since Bundler::Thor commands can be added to a sandbox, this method is also responsable for removing the sandbox namespace.

This method should not be used in general because it's used to deal with older versions of Bundler::Thor. On current versions, if you need to get the namespace from a class, just call namespace on it.

#### Parameters¶ ↑

constant<Object>

  The constant to be converted to the thor path.

#### Returns¶ ↑

`String`

  If we receive Foo::Bar::Baz it returns “foo:bar:baz”

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 43
    def namespace_from_thor_class(constant)
      constant = constant.to_s.gsub(/^Bundler::Thor::Sandbox::/, "")
      constant = snake_case(constant).squeeze(":")
      constant
    end

namespaces_in_content(contents, file = __FILE__) click to toggle source

Given the contents, evaluate it inside the sandbox and returns the namespaces defined in the sandbox.

#### Parameters¶ ↑

contents<String>

#### Returns¶ ↑

Array

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 58
    def namespaces_in_content(contents, file = __FILE__)
      old_constants = Bundler::Thor::Base.subclasses.dup
      Bundler::Thor::Base.subclasses.clear

      load_thorfile(file, contents)

      new_constants = Bundler::Thor::Base.subclasses.dup
      Bundler::Thor::Base.subclasses.replace(old_constants)

      new_constants.map!(&:namespace)
      new_constants.compact!
      new_constants
    end

ruby_command() click to toggle source

Return the path to the ruby interpreter taking into account multiple installations and windows extensions.

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 220
    def ruby_command
      @ruby_command ||= begin
        ruby_name = RbConfig::CONFIG["ruby_install_name"]
        ruby = File.join(RbConfig::CONFIG["bindir"], ruby_name)
        ruby << RbConfig::CONFIG["EXEEXT"]

        # avoid using different name than ruby (on platforms supporting links)
        if ruby_name != "ruby" && File.respond_to?(:readlink)
          begin
            alternate_ruby = File.join(RbConfig::CONFIG["bindir"], "ruby")
            alternate_ruby << RbConfig::CONFIG["EXEEXT"]

            # ruby is a symlink
            if File.symlink? alternate_ruby
              linked_ruby = File.readlink alternate_ruby

              # symlink points to 'ruby_install_name'
              ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
            end
          rescue NotImplementedError # rubocop:disable HandleExceptions
            # just ignore on windows
          end
        end

        # escape string in case path to ruby executable contain spaces.
        ruby.sub!(/.*\s.*/m, '"\&"')
        ruby
      end
    end

snake_case(str) click to toggle source

Receives a string and convert it to snake case. SnakeCase returns snake_case.

#### Parameters¶ ↑

`String`

#### Returns¶ ↑

`String`

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 90
    def snake_case(str)
      return str.downcase if str =~ /^[A-Z_]+$/
      str.gsub(/\B[A-Z]/, '_\&').squeeze("_") =~ /_*(.*)/
      $+.downcase
    end

thor_classes_in(klass) click to toggle source

Returns the thor classes declared inside the given class.

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 74
    def thor_classes_in(klass)
      stringfied_constants = klass.constants.map(&:to_s)
      Bundler::Thor::Base.subclasses.select do |subclass|
        next unless subclass.name
        stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", ""))
      end
    end

thor_root() click to toggle source

Returns the root where thor files are located, depending on the OS.

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 191
    def thor_root
      File.join(user_home, ".thor").tr('\\', "/")
    end

thor_root_glob() click to toggle source

Returns the files in the thor root. On Windows `thor_root` will be something like this:

    C:\Documents and Settings\james\.thor

If we don't gsub the \ character, `Dir.glob` will fail.

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 202
    def thor_root_glob
      files = Dir["#{escape_globs(thor_root)}/*"]

      files.map! do |file|
        File.directory?(file) ? File.join(file, "main.thor") : file
      end
    end

user_home() click to toggle source

    # File lib/bundler/vendor/thor/lib/thor/util.rb, line 167
    def user_home
      @@user_home ||= if ENV["HOME"]
        ENV["HOME"]
      elsif ENV["USERPROFILE"]
        ENV["USERPROFILE"]
      elsif ENV["HOMEDRIVE"] && ENV["HOMEPATH"]
        File.join(ENV["HOMEDRIVE"], ENV["HOMEPATH"])
      elsif ENV["APPDATA"]
        ENV["APPDATA"]
      else
        begin
          File.expand_path("~")
        rescue
          if File::ALT_SEPARATOR
            "C:/"
          else
            "/"
          end
        end
      end
    end