Module: Poise::Utils

Extended by:
Utils
Included in:
Utils
Defined in:
lib/poise/utils.rb,
lib/poise/utils/shell_out.rb,
lib/poise/utils/resource_provider_mixin.rb

Defined Under Namespace

Modules: ResourceProviderMixin, ShellOut

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.ancestor_send(obj, msg, *args, default: nil, ignore: [default]) ⇒ Object

Try to find an ancestor to call a method on.

Examples:

val = @val || Poise::Utils.ancestor_send(self, :val)

Parameters:

  • obj (Object)

    Self from the caller.

  • msg (Symbol)

    Method to try to call.

  • args (Array<Object>)

    Method arguments.

  • default (Object) (defaults to: nil)

    Default return value if no valid ancestor exists.

  • ignore (Array<Object>) (defaults to: [default])

    Return value to ignore when scanning ancesors.

Returns:

  • (Object)

Since:

  • 2.2.3

  • 2.3.0 Added ignore parameter.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/poise/utils.rb', line 83

def ancestor_send(obj, msg, *args, default: nil, ignore: [default])
  # Class is a subclass of Module, if we get something else use its class.
  obj = obj.class unless obj.is_a?(Module)
  ancestors = []
  if obj.respond_to?(:superclass)
    # Check the superclass first if present.
    ancestors << obj.superclass
  end
  # Make sure we don't check obj itself.
  ancestors.concat(obj.ancestors.drop(1))
  ancestors.each do |mod|
    if mod.respond_to?(msg)
      val = mod.send(msg, *args)
      # If we get the default back, assume we should keep trying.
      return val unless ignore.include?(val)
    end
  end
  # Nothing valid found, use the default.
  default
end

.find_cookbook_name(run_context, filename) ⇒ String

Find the cookbook name for a given filename. The can used to find the cookbook that corresponds to a caller of a file.

Examples:

def my_thing
  caller_filename = caller.first.split(':').first
  cookbook = Poise::Utils.find_cookbook_name(run_context, caller_filename)
  # ...
end

Parameters:

  • run_context (Chef::RunContext)

    Context to check.

  • filename (String)

    Absolute filename to check for.

Returns:

  • (String)

Raises:



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/poise/utils.rb', line 39

def find_cookbook_name(run_context, filename)
  possibles = {}
  Poise.debug("[Poise] Checking cookbook for #{filename.inspect}")
  run_context.cookbook_collection.each do |name, ver|
    # This special method is added by Halite::Gem#as_cookbook_version.
    if ver.respond_to?(:halite_root)
      # The join is there because ../poise-ruby/lib starts with ../poise so
      # we want a trailing /.
      if filename.start_with?(File.join(ver.halite_root, ''))
        Poise.debug("[Poise] Found matching halite_root in #{name}: #{ver.halite_root.inspect}")
        possibles[ver.halite_root] = name
      end
    else
      Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |seg|
        ver.segment_filenames(seg).each do |file|
          # Put this behind an environment variable because it is verbose
          # even for normal debugging-level output.
          Poise.debug("[Poise] Checking #{seg} in #{name}: #{file.inspect}")
          if file == filename
            Poise.debug("[Poise] Found matching #{seg} in #{name}: #{file.inspect}")
            possibles[file] = name
          end
        end
      end
    end
  end
  raise Poise::Error.new("Unable to find cookbook for file #{filename.inspect}") if possibles.empty?
  # Sort the items by matching path length, pick the name attached to the longest.
  possibles.sort_by{|key, value| key.length }.last[1]
end

.parameterized_module(mod, &block)

This method returns an undefined value.

Create a helper to invoke a module with some parameters.

Examples:

module MyMixin
  def self.my_mixin_name(name)
    # ...
  end
end

Poise::Utils.parameterized_module(MyMixin) do |name|
  my_mixin_name(name)
end

Parameters:

  • mod (Module)

    The module to wrap.

  • block (Proc)

    The module to implement to parameterization.

Raises:

Since:

  • 2.3.0



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/poise/utils.rb', line 120

def parameterized_module(mod, &block)
  raise Poise::Error.new("Cannot parameterize an anonymous module") unless mod.name && !mod.name.empty?
  parent_name_parts = mod.name.split(/::/)
  # Grab the last piece which will be the method name.
  mod_name = parent_name_parts.pop
  # Find the enclosing module or class object.
  parent = parent_name_parts.inject(Object) {|memo, name| memo.const_get(name) }
  # Object is a special case since we need #define_method instead.
  method_type = if parent == Object
    :define_method
  else
    :define_singleton_method
  end
  # Scoping hack.
  self_ = self
  # Construct the method.
  parent.send(method_type, mod_name) do |*args|
    self_.send(:check_block_arity!, block, args)
    # Create a new anonymous module to be returned from the method.
    Module.new do
      # Fake the name.
      define_singleton_method(:name) do
        super() || mod.name
      end

      # When the stub module gets included, activate our behaviors.
      define_singleton_method(:included) do |klass|
        super(klass)
        klass.send(:include, mod)
        klass.instance_exec(*args, &block)
      end
    end
  end
end

Instance Method Details

#ancestor_send(obj, msg, *args, default: nil, ignore: [default]) ⇒ Object

Try to find an ancestor to call a method on.

Examples:

val = @val || Poise::Utils.ancestor_send(self, :val)

Parameters:

  • obj (Object)

    Self from the caller.

  • msg (Symbol)

    Method to try to call.

  • args (Array<Object>)

    Method arguments.

  • default (Object) (defaults to: nil)

    Default return value if no valid ancestor exists.

  • ignore (Array<Object>) (defaults to: [default])

    Return value to ignore when scanning ancesors.

Returns:

  • (Object)

Since:

  • 2.2.3

  • 2.3.0 Added ignore parameter.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/poise/utils.rb', line 83

def ancestor_send(obj, msg, *args, default: nil, ignore: [default])
  # Class is a subclass of Module, if we get something else use its class.
  obj = obj.class unless obj.is_a?(Module)
  ancestors = []
  if obj.respond_to?(:superclass)
    # Check the superclass first if present.
    ancestors << obj.superclass
  end
  # Make sure we don't check obj itself.
  ancestors.concat(obj.ancestors.drop(1))
  ancestors.each do |mod|
    if mod.respond_to?(msg)
      val = mod.send(msg, *args)
      # If we get the default back, assume we should keep trying.
      return val unless ignore.include?(val)
    end
  end
  # Nothing valid found, use the default.
  default
end

#find_cookbook_name(run_context, filename) ⇒ String

Find the cookbook name for a given filename. The can used to find the cookbook that corresponds to a caller of a file.

Examples:

def my_thing
  caller_filename = caller.first.split(':').first
  cookbook = Poise::Utils.find_cookbook_name(run_context, caller_filename)
  # ...
end

Parameters:

  • run_context (Chef::RunContext)

    Context to check.

  • filename (String)

    Absolute filename to check for.

Returns:

  • (String)

Raises:



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/poise/utils.rb', line 39

def find_cookbook_name(run_context, filename)
  possibles = {}
  Poise.debug("[Poise] Checking cookbook for #{filename.inspect}")
  run_context.cookbook_collection.each do |name, ver|
    # This special method is added by Halite::Gem#as_cookbook_version.
    if ver.respond_to?(:halite_root)
      # The join is there because ../poise-ruby/lib starts with ../poise so
      # we want a trailing /.
      if filename.start_with?(File.join(ver.halite_root, ''))
        Poise.debug("[Poise] Found matching halite_root in #{name}: #{ver.halite_root.inspect}")
        possibles[ver.halite_root] = name
      end
    else
      Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |seg|
        ver.segment_filenames(seg).each do |file|
          # Put this behind an environment variable because it is verbose
          # even for normal debugging-level output.
          Poise.debug("[Poise] Checking #{seg} in #{name}: #{file.inspect}")
          if file == filename
            Poise.debug("[Poise] Found matching #{seg} in #{name}: #{file.inspect}")
            possibles[file] = name
          end
        end
      end
    end
  end
  raise Poise::Error.new("Unable to find cookbook for file #{filename.inspect}") if possibles.empty?
  # Sort the items by matching path length, pick the name attached to the longest.
  possibles.sort_by{|key, value| key.length }.last[1]
end

#parameterized_module(mod, &block)

This method returns an undefined value.

Create a helper to invoke a module with some parameters.

Examples:

module MyMixin
  def self.my_mixin_name(name)
    # ...
  end
end

Poise::Utils.parameterized_module(MyMixin) do |name|
  my_mixin_name(name)
end

Parameters:

  • mod (Module)

    The module to wrap.

  • block (Proc)

    The module to implement to parameterization.

Raises:

Since:

  • 2.3.0



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/poise/utils.rb', line 120

def parameterized_module(mod, &block)
  raise Poise::Error.new("Cannot parameterize an anonymous module") unless mod.name && !mod.name.empty?
  parent_name_parts = mod.name.split(/::/)
  # Grab the last piece which will be the method name.
  mod_name = parent_name_parts.pop
  # Find the enclosing module or class object.
  parent = parent_name_parts.inject(Object) {|memo, name| memo.const_get(name) }
  # Object is a special case since we need #define_method instead.
  method_type = if parent == Object
    :define_method
  else
    :define_singleton_method
  end
  # Scoping hack.
  self_ = self
  # Construct the method.
  parent.send(method_type, mod_name) do |*args|
    self_.send(:check_block_arity!, block, args)
    # Create a new anonymous module to be returned from the method.
    Module.new do
      # Fake the name.
      define_singleton_method(:name) do
        super() || mod.name
      end

      # When the stub module gets included, activate our behaviors.
      define_singleton_method(:included) do |klass|
        super(klass)
        klass.send(:include, mod)
        klass.instance_exec(*args, &block)
      end
    end
  end
end