Ruby: Include send example in qhelp

This commit is contained in:
Harry Maclean
2022-12-28 11:34:55 +13:00
parent d3812f5906
commit a6571a05ab
3 changed files with 14 additions and 8 deletions

View File

@@ -69,7 +69,7 @@ to define the getter method.
<example>
<p>
This example dynamically registers a method on another class which
forwards its arguments to the registering module. This approach uses
forwards its arguments to a target class. This approach uses
<code>module_eval</code> and string interpolation to construct class variables
and methods.
</p>
@@ -81,6 +81,12 @@ A safer approach is to use <code>class_variable_set</code> and
<code>class_variable_get</code> along with <code>define_method</code>. String
interpolation is still used to construct the class variable name, but this is
safe because <code>class_variable_set<code> is not susceptible to code injection.
To construct a dynamic method call we use <code>send</code>, which is ulnerable
to code injection: if an attacker can control the first argument, they can call
any method on the receiver. However this is less powerful than being able to run
arbitrary Ruby code, so it is an improvement in security. We also document to
callers that they should not pass arbitrary user data to the <code>name</code>
parameter.
</p>
<sample src="examples/UnsafeCodeConstruction3Safe.rb" />

View File

@@ -1,11 +1,10 @@
module Invoker
def attach(klass, name)
invoker = self
def attach(klass, name, target)
klass.module_eval <<-CODE
@@#{name} = invoker
@@#{name} = target
def #{name}(*args)
@@#{name}.call(*args)
@@#{name}.#{name}(*args)
end
CODE
end

View File

@@ -1,9 +1,10 @@
module Invoker
def attach(klass, name)
# Do not pass arbitrary user input to +name+.
def attach(klass, name, target)
var = :"@@#{name}"
klass.class_variable_set(var, self)
klass.class_variable_set(var, target)
klass.define_method(name) do |*args|
self.class.class_variable_get(var).call(*args)
self.class.class_variable_get(var).send(name, *args)
end
end
end