class Vega::Spec
Constants
- JSON_ESCAPE
from github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/string/output_safety.rb
- JSON_ESCAPE_REGEXP
Public Class Methods
new(spec)
click to toggle source
# File lib/vega/spec.rb, line 3 def initialize(spec) spec = spec.spec if spec.respond_to?(:spec) raise ArgumentError, "Expected Hash, not #{spec.class.name}" unless spec.is_a?(Hash) @spec = spec.transform_keys!(&:to_s) end
Public Instance Methods
to_iruby()
click to toggle source
TODO only load vega-lite if $schema requires it
# File lib/vega/spec.rb, line 21 def to_iruby html, js = generate_output output = <<~EOS #{html} <script> require.config({ paths: { 'vega': 'https://cdn.jsdelivr.net/npm/vega@5.19.1?noext', 'vega-lite': 'https://cdn.jsdelivr.net/npm/vega-lite@4.17.0?noext', 'vega-embed': 'https://cdn.jsdelivr.net/npm/vega-embed@6.15.1?noext' } }); require(['vega', 'vega-lite', 'vega-embed'], function(vega, vegaLite, vegaEmbed) { #{js} }); </script> EOS ["text/html", output] end
to_s()
click to toggle source
# File lib/vega/spec.rb, line 9 def to_s html, js = generate_output output = <<~EOS #{html} <script> #{js} </script> EOS output.respond_to?(:html_safe) ? output.html_safe : output end
Private Instance Methods
generate_output()
click to toggle source
# File lib/vega/spec.rb, line 43 def generate_output id = "chart-#{SecureRandom.hex(16)}" # 2**128 values width = @spec["width"].is_a?(Integer) ? "#{@spec["width"]}px" : "100%" height = @spec["height"].is_a?(Integer) ? "#{@spec["height"]}px" : "300px" # user can override with usermeta: {embedOptions: ...} embed_options = {actions: false} # html vars html_vars = { id: id } html_vars.each_key do |k| html_vars[k] = ERB::Util.html_escape(html_vars[k]) end # css vars css_vars = { height: height, width: width } css_vars.each_key do |k| # limit to alphanumeric and % for simplicity # this prevents things like calc() but safety is the priority raise ArgumentError, "Invalid #{k}" unless css_vars[k] =~ /\A[a-zA-Z0-9%]*\z/ # we limit above, but escape for safety as fail-safe # to prevent XSS injection in worse-case scenario css_vars[k] = ERB::Util.html_escape(css_vars[k]) end # js vars js_vars = { el: "##{id}", spec: @spec, opt: embed_options } js_vars.each_key do |k| js_vars[k] = json_escape(js_vars[k].to_json) end # needs width to be set for vegaEmbed to work html = %(<div id="%{id}" style="width: %{width}; height: %{height};"></div>) % html_vars.merge(css_vars) js = "vegaEmbed(%{el}, %{spec}, %{opt});" % js_vars [html, js] end
json_escape(s)
click to toggle source
# File lib/vega/spec.rb, line 93 def json_escape(s) if ERB::Util.respond_to?(:json_escape) ERB::Util.json_escape(s) else s.to_s.gsub(JSON_ESCAPE_REGEXP, JSON_ESCAPE) end end