Module: FEELIN
- Defined in:
- lib/feelin.rb,
lib/feelin/version.rb
Constant Summary collapse
- BUNDLE_PATH =
Pre-built single-file IIFE bundle (feelin + its dependencies), produced by ‘npm run build` in lib/feelin/js. It exposes the feelin API on the global `feel`. feelin is distributed as an ES module, so it is bundled ahead of time rather than assembled at load time.
File.("feelin/js/dist/feelin.js", __dir__)
- VERSION =
"7.0.1"- @@functions =
Set.new
Class Method Summary collapse
- .add_function(name, proc) ⇒ Object
-
.evaluate(expression, context = nil) ⇒ Object
NOTE: the context is serialized to JSON and interpolated into the eval, rather than passed as a native Ruby object via MiniRacer#call.
-
.serialize_context(context) ⇒ Object
Builds the JS evaluation context.
- .unary_test(expression, value, context = {}) ⇒ Object
-
.unwrap(result) ⇒ Object
feelin (>= 7) returns an EvaluationResult ‘{ value, warnings }`; callers expect the bare value.
Class Method Details
.add_function(name, proc) ⇒ Object
30 31 32 33 |
# File 'lib/feelin.rb', line 30 def self.add_function(name, proc) @@functions.add(name) @@context.attach(name, proc) end |
.evaluate(expression, context = nil) ⇒ Object
NOTE: the context is serialized to JSON and interpolated into the eval, rather than passed as a native Ruby object via MiniRacer#call. That was measured to be ~15-20% FASTER: JSON.generate © plus V8’s highly-optimized parsing beats mini_racer’s element-by-element Ruby->V8 marshalling, and it lets custom functions be injected straight into the context (no per-call merge).
18 19 20 21 22 |
# File 'lib/feelin.rb', line 18 def self.evaluate(expression, context = nil) context_json = serialize_context(context) unwrap(@@context.eval("feel.evaluate(#{JSON.generate(expression)}, #{context_json})")) end |
.serialize_context(context) ⇒ Object
Builds the JS evaluation context. When custom functions are registered they must be injected into every context as forwarders to their attached globals. Each function is emitted as a QUOTED key forwarding to globalThis so that names containing spaces (e.g. “string join”) are valid JS; an empty context is coerced to nil to avoid producing an invalid “,…” literal. The ‘(…args)` forwarder is deliberate: feelin reads a function’s source to learn its parameters, so a bare reference to the (native) attached global would be seen as taking no arguments.
51 52 53 54 55 56 57 58 59 60 |
# File 'lib/feelin.rb', line 51 def self.serialize_context(context) return JSON.generate(context) if @@functions.empty? context = nil if context.respond_to?(:empty?) && context.empty? functions_json = @@functions.map do |name| %("#{name}":function(...args){return globalThis["#{name}"](...args)}) end.join(",") context.nil? ? "{#{functions_json}}" : "#{JSON.generate(context)[0...-1]},#{functions_json}}" end |
.unary_test(expression, value, context = {}) ⇒ Object
24 25 26 27 28 |
# File 'lib/feelin.rb', line 24 def self.unary_test(expression, value, context = {}) context_json = serialize_context({ **context, '?' => value }) unwrap(@@context.eval("feel.unaryTest(#{JSON.generate(expression)}, #{context_json})")) end |
.unwrap(result) ⇒ Object
feelin (>= 7) returns an EvaluationResult ‘{ value, warnings }`; callers expect the bare value.
39 40 41 |
# File 'lib/feelin.rb', line 39 def self.unwrap(result) result.is_a?(Hash) && result.key?("warnings") ? result["value"] : result end |