2021-05-10 12:26:41 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-01-14 18:55:16 -05:00
|
|
|
require "docile/version"
|
|
|
|
require "docile/execution"
|
|
|
|
require "docile/fallback_context_proxy"
|
|
|
|
require "docile/chaining_fallback_context_proxy"
|
2019-10-22 13:29:58 -04:00
|
|
|
require "docile/backtrace_filter"
|
2011-12-06 13:51:56 -05:00
|
|
|
|
2013-07-29 00:14:15 -04:00
|
|
|
# Docile keeps your Ruby DSLs tame and well-behaved.
|
2011-12-06 13:51:56 -05:00
|
|
|
module Docile
|
2013-07-29 00:06:43 -04:00
|
|
|
extend Execution
|
|
|
|
|
2013-07-28 16:24:39 -04:00
|
|
|
# Execute a block in the context of an object whose methods represent the
|
|
|
|
# commands in a DSL.
|
2011-12-06 14:46:46 -05:00
|
|
|
#
|
2013-07-28 16:24:39 -04:00
|
|
|
# @note Use with an *imperative* DSL (commands modify the context object)
|
2011-12-06 18:46:14 -05:00
|
|
|
#
|
2013-07-28 16:24:39 -04:00
|
|
|
# Use this method to execute an *imperative* DSL, which means that:
|
2011-12-06 14:46:46 -05:00
|
|
|
#
|
2013-07-28 23:57:25 -04:00
|
|
|
# 1. Each command mutates the state of the DSL context object
|
|
|
|
# 2. The return value of each command is ignored
|
|
|
|
# 3. The final return value is the original context object
|
2013-07-28 16:24:39 -04:00
|
|
|
#
|
|
|
|
# @example Use a String as a DSL
|
|
|
|
# Docile.dsl_eval("Hello, world!") do
|
|
|
|
# reverse!
|
|
|
|
# upcase!
|
|
|
|
# end
|
|
|
|
# #=> "!DLROW ,OLLEH"
|
|
|
|
#
|
|
|
|
# @example Use an Array as a DSL
|
|
|
|
# Docile.dsl_eval([]) do
|
|
|
|
# push 1
|
|
|
|
# push 2
|
|
|
|
# pop
|
|
|
|
# push 3
|
|
|
|
# end
|
|
|
|
# #=> [1, 3]
|
|
|
|
#
|
|
|
|
# @param dsl [Object] context object whose methods make up the DSL
|
2013-04-01 16:40:26 -04:00
|
|
|
# @param args [Array] arguments to be passed to the block
|
2013-08-02 15:45:12 -04:00
|
|
|
# @param block [Proc] the block of DSL commands to be executed against the
|
2013-07-28 16:24:39 -04:00
|
|
|
# `dsl` context object
|
|
|
|
# @return [Object] the `dsl` context object after executing the block
|
2013-03-31 23:27:12 -04:00
|
|
|
def dsl_eval(dsl, *args, &block)
|
2013-07-28 19:36:03 -04:00
|
|
|
exec_in_proxy_context(dsl, FallbackContextProxy, *args, &block)
|
2011-12-06 14:46:46 -05:00
|
|
|
dsl
|
|
|
|
end
|
2021-01-11 17:03:24 -05:00
|
|
|
|
|
|
|
ruby2_keywords :dsl_eval if respond_to?(:ruby2_keywords, true)
|
2011-12-06 14:46:46 -05:00
|
|
|
module_function :dsl_eval
|
2013-07-28 19:22:45 -04:00
|
|
|
|
2018-01-11 14:27:50 -05:00
|
|
|
# Execute a block in the context of an object whose methods represent the
|
2018-01-11 17:42:12 -05:00
|
|
|
# commands in a DSL, and return *the block's return value*.
|
2018-01-11 14:27:50 -05:00
|
|
|
#
|
|
|
|
# @note Use with an *imperative* DSL (commands modify the context object)
|
|
|
|
#
|
|
|
|
# Use this method to execute an *imperative* DSL, which means that:
|
|
|
|
#
|
|
|
|
# 1. Each command mutates the state of the DSL context object
|
|
|
|
# 2. The return value of each command is ignored
|
|
|
|
# 3. The final return value is the original context object
|
|
|
|
#
|
|
|
|
# @example Use a String as a DSL
|
2018-01-11 17:42:12 -05:00
|
|
|
# Docile.dsl_eval_with_block_return("Hello, world!") do
|
2018-01-11 14:27:50 -05:00
|
|
|
# reverse!
|
|
|
|
# upcase!
|
|
|
|
# first
|
|
|
|
# end
|
|
|
|
# #=> "!"
|
|
|
|
#
|
|
|
|
# @example Use an Array as a DSL
|
2018-01-11 17:42:12 -05:00
|
|
|
# Docile.dsl_eval_with_block_return([]) do
|
2018-01-11 14:27:50 -05:00
|
|
|
# push "a"
|
|
|
|
# push "b"
|
|
|
|
# pop
|
|
|
|
# push "c"
|
|
|
|
# length
|
|
|
|
# end
|
|
|
|
# #=> 2
|
|
|
|
#
|
|
|
|
# @param dsl [Object] context object whose methods make up the DSL
|
|
|
|
# @param args [Array] arguments to be passed to the block
|
|
|
|
# @param block [Proc] the block of DSL commands to be executed against the
|
|
|
|
# `dsl` context object
|
|
|
|
# @return [Object] the return value from executing the block
|
|
|
|
def dsl_eval_with_block_return(dsl, *args, &block)
|
|
|
|
exec_in_proxy_context(dsl, FallbackContextProxy, *args, &block)
|
|
|
|
end
|
2021-01-11 17:03:24 -05:00
|
|
|
|
2021-05-10 12:26:41 -04:00
|
|
|
if respond_to?(:ruby2_keywords, true)
|
|
|
|
ruby2_keywords :dsl_eval_with_block_return
|
|
|
|
end
|
2018-01-11 14:27:50 -05:00
|
|
|
module_function :dsl_eval_with_block_return
|
|
|
|
|
2013-07-28 23:57:25 -04:00
|
|
|
# Execute a block in the context of an immutable object whose methods,
|
|
|
|
# and the methods of their return values, represent the commands in a DSL.
|
|
|
|
#
|
|
|
|
# @note Use with a *functional* DSL (commands return successor
|
|
|
|
# context objects)
|
|
|
|
#
|
|
|
|
# Use this method to execute a *functional* DSL, which means that:
|
|
|
|
#
|
|
|
|
# 1. The original DSL context object is never mutated
|
|
|
|
# 2. Each command returns the next DSL context object
|
|
|
|
# 3. The final return value is the value returned by the last command
|
|
|
|
#
|
2013-07-29 00:14:15 -04:00
|
|
|
# @example Use a frozen String as a DSL
|
|
|
|
# Docile.dsl_eval_immutable("I'm immutable!".freeze) do
|
2013-07-28 23:57:25 -04:00
|
|
|
# reverse
|
|
|
|
# upcase
|
|
|
|
# end
|
2013-07-29 00:14:15 -04:00
|
|
|
# #=> "!ELBATUMMI M'I"
|
2013-07-28 23:57:25 -04:00
|
|
|
#
|
|
|
|
# @example Use a Float as a DSL
|
|
|
|
# Docile.dsl_eval_immutable(84.5) do
|
|
|
|
# fdiv(2)
|
|
|
|
# floor
|
|
|
|
# end
|
|
|
|
# #=> 42
|
|
|
|
#
|
|
|
|
# @param dsl [Object] immutable context object whose methods make up the
|
|
|
|
# initial DSL
|
|
|
|
# @param args [Array] arguments to be passed to the block
|
2013-08-02 15:45:12 -04:00
|
|
|
# @param block [Proc] the block of DSL commands to be executed against the
|
2013-07-28 23:57:25 -04:00
|
|
|
# `dsl` context object and successor return values
|
|
|
|
# @return [Object] the return value of the final command in the block
|
2013-07-28 19:22:45 -04:00
|
|
|
def dsl_eval_immutable(dsl, *args, &block)
|
2013-07-28 19:36:03 -04:00
|
|
|
exec_in_proxy_context(dsl, ChainingFallbackContextProxy, *args, &block)
|
|
|
|
end
|
2021-05-04 10:55:36 -04:00
|
|
|
|
2021-01-11 17:03:24 -05:00
|
|
|
ruby2_keywords :dsl_eval_immutable if respond_to?(:ruby2_keywords, true)
|
2013-07-28 19:36:03 -04:00
|
|
|
module_function :dsl_eval_immutable
|
2011-12-06 13:51:56 -05:00
|
|
|
end
|