plot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/js/bun_runner.js +33 -0
- data/lib/js/context.js +16 -0
- data/lib/plot/mark.rb +89 -0
- data/lib/plot/plot.rb +54 -0
- data/lib/plot.rb +46 -0
- metadata +49 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 67d6a3629080da18f0e3a73f6d8c49454c32698e54581c8b7bf8744c4773649c
|
4
|
+
data.tar.gz: c4456dfbd322ae85cfe26e26e063122942922d9781eb4649a82351c8811b54d8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6afb6dd820edb324e75f3478610dcee2fb2798e909471c11b91dad7152ace8bd336b837fc646b7a5d1d6911c4d72d6ff223d91d5b82e61df1411da8a249a1d29
|
7
|
+
data.tar.gz: 665f0c522e9e9c37ba2093972367ff5a5115df26efa34300ecaef5606170a281a857333dfb2010cea1a2d5426029815fc21b1d928bfeb28fef7b339e1b6b3d5d
|
@@ -0,0 +1,33 @@
|
|
1
|
+
(function(program, execJS) { (function() {execJS(program) }).call({}); })(async function() { #{source}
|
2
|
+
}, function(program) {
|
3
|
+
// Force BunJS to use sloppy mode see https://github.com/oven-sh/bun/issues/4527#issuecomment-1709520894
|
4
|
+
exports.abc = function(){}
|
5
|
+
var __process__ = process;
|
6
|
+
var printFinal = function(string) {
|
7
|
+
process.stdout.write('' + string, function() {
|
8
|
+
__process__.exit(0);
|
9
|
+
});
|
10
|
+
};
|
11
|
+
try {
|
12
|
+
//delete this.process;
|
13
|
+
//delete this.console;
|
14
|
+
(program()).then((result) => {
|
15
|
+
process = __process__;
|
16
|
+
if (typeof result == 'undefined' && result !== null) {
|
17
|
+
printFinal('["ok"]');
|
18
|
+
} else {
|
19
|
+
try {
|
20
|
+
printFinal(JSON.stringify(['ok', result]));
|
21
|
+
} catch (err) {
|
22
|
+
printFinal(JSON.stringify(['err', '' + err, err.stack]));
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}).catch((err) => {
|
26
|
+
process = __process__;
|
27
|
+
printFinal(JSON.stringify(['err', '' + err, err.stack]));
|
28
|
+
})
|
29
|
+
} catch (err) {
|
30
|
+
process = __process__;
|
31
|
+
printFinal(JSON.stringify(['err', '' + err, err.stack]));
|
32
|
+
}
|
33
|
+
});
|
data/lib/js/context.js
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
const Plot = await import('@observablehq/plot');
|
2
|
+
const d3 = await import('d3');
|
3
|
+
const { JSDOM } = (await import('jsdom')).default;
|
4
|
+
|
5
|
+
const jsdom = new JSDOM("")
|
6
|
+
|
7
|
+
global.window = jsdom.window
|
8
|
+
global.document = jsdom.window.document
|
9
|
+
global.navigator = jsdom.window.navigator
|
10
|
+
global.Event = jsdom.window.Event
|
11
|
+
global.Node = jsdom.window.Node
|
12
|
+
global.NodeList = jsdom.window.NodeList
|
13
|
+
global.HTMLCollection = jsdom.window.HTMLCollection
|
14
|
+
|
15
|
+
global.d3 = d3
|
16
|
+
global.Plot = Plot
|
data/lib/plot/mark.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
class Plot::MarkProxy
|
2
|
+
def initialize(mark, type)
|
3
|
+
@mark = mark
|
4
|
+
@mark.type = type
|
5
|
+
end
|
6
|
+
|
7
|
+
def channel(name, value, **obj)
|
8
|
+
# TODO: add checking if option is a channel
|
9
|
+
obj[:value] = value
|
10
|
+
@mark.add_option(name, obj)
|
11
|
+
end
|
12
|
+
|
13
|
+
def option(name, value)
|
14
|
+
if(value.class == Proc || [:title, :href, :ariaLabel].include?(name)) then
|
15
|
+
raise "A channel should be used in place of option"
|
16
|
+
end
|
17
|
+
@mark.add_option(name, { value: value })
|
18
|
+
end
|
19
|
+
|
20
|
+
def style(name, value)
|
21
|
+
if([:fill,
|
22
|
+
:fillOpacity,
|
23
|
+
:stroke,
|
24
|
+
:strokeWidth,
|
25
|
+
:strokeOpacity,
|
26
|
+
:strokeLinejoin,
|
27
|
+
:strokeLinecap,
|
28
|
+
:strokeMiterlimit,
|
29
|
+
:strokeDasharray,
|
30
|
+
:strokeDashoffset,
|
31
|
+
:opacity,
|
32
|
+
:mixBlendMode,
|
33
|
+
:imageFilter,
|
34
|
+
:shapeRendering,
|
35
|
+
:paintOrder,
|
36
|
+
:dx,
|
37
|
+
:dy,
|
38
|
+
:target,
|
39
|
+
:ariaDescription,
|
40
|
+
:ariaHidden,
|
41
|
+
:pointerEvents,
|
42
|
+
:clip,
|
43
|
+
:tip].include? name)
|
44
|
+
then
|
45
|
+
@mark.add_option(name, value)
|
46
|
+
else
|
47
|
+
raise "Not a style option"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
class Plot::Mark
|
55
|
+
|
56
|
+
attr_accessor :type, :options
|
57
|
+
|
58
|
+
def initialize(type, **options)
|
59
|
+
@type = type
|
60
|
+
@options = options
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_option(k, v)
|
64
|
+
@options[k.to_s] = v
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def render(data)
|
69
|
+
@options.values do |o|
|
70
|
+
if o.try(:value).try(:lambda?)
|
71
|
+
output = []
|
72
|
+
data.each? do |obj|
|
73
|
+
output.push(o.call(obj))
|
74
|
+
end
|
75
|
+
|
76
|
+
o.value = output
|
77
|
+
end
|
78
|
+
|
79
|
+
if o.try(:transform).try(:lambda?)
|
80
|
+
o.value = o.transform.call(data).to_a
|
81
|
+
o.transform = nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
"Plot['#{@type}'](JSON.parse('#{JSON.generate(data)}'), JSON.parse('#{JSON.generate(@options)}'))"
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
end
|
data/lib/plot/plot.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
class Plot::Plot
|
2
|
+
|
3
|
+
attr_accessor :data
|
4
|
+
|
5
|
+
def initialize(**data)
|
6
|
+
@data = data
|
7
|
+
end
|
8
|
+
|
9
|
+
def render
|
10
|
+
self.class::definition.render(@data)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Rails renderable
|
14
|
+
def render_in(view_context)
|
15
|
+
view_context.render html: render.html_safe
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Plot::PlotProxy
|
20
|
+
|
21
|
+
def initialize(plot)
|
22
|
+
@plot = plot
|
23
|
+
end
|
24
|
+
|
25
|
+
def mark(type, id, &block)
|
26
|
+
mark = Plot::Mark.new(nil)
|
27
|
+
mark_proxy = Plot::MarkProxy.new(mark, type)
|
28
|
+
mark_proxy.instance_eval(&block)
|
29
|
+
@plot.add_mark(id, mark)
|
30
|
+
end
|
31
|
+
|
32
|
+
def plot_options(**options)
|
33
|
+
@plot.options = options
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
class Plot::PlotDefinition
|
39
|
+
|
40
|
+
attr_accessor :marks, :options
|
41
|
+
|
42
|
+
def initialize(marks, **options)
|
43
|
+
@marks = marks.to_h
|
44
|
+
@options = options
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_mark(id, mark)
|
48
|
+
@marks[id.to_s] = mark
|
49
|
+
end
|
50
|
+
|
51
|
+
def render(data)
|
52
|
+
Plot.plot(@marks, data, @options)
|
53
|
+
end
|
54
|
+
end
|
data/lib/plot.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "execjs"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Plot
|
5
|
+
@source = open(Gem.loaded_specs["plot"].gem_dir + "/lib/js/context.js").read
|
6
|
+
|
7
|
+
@runtime = ExecJS::ExternalRuntime.new(
|
8
|
+
name: "Bun.sh Async",
|
9
|
+
command: ["bun"],
|
10
|
+
runner_path: Gem.loaded_specs["plot"].gem_dir + "/lib/js/bun_runner.js",
|
11
|
+
encoding: 'UTF-8'
|
12
|
+
)
|
13
|
+
|
14
|
+
@context = @runtime.compile(@source)
|
15
|
+
|
16
|
+
def self._context
|
17
|
+
@context
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.encode_source(source)
|
21
|
+
@runtime.send(:encode_source,source)
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def self.define(&block)
|
26
|
+
definition = PlotDefinition.new(nil)
|
27
|
+
plot_proxy = PlotProxy.new(definition)
|
28
|
+
plot_proxy.instance_eval(&block)
|
29
|
+
return definition
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def self.call(method, *args)
|
34
|
+
puts *args
|
35
|
+
@context.call("Plot['#{method}']", *args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.plot(marks, data, options)
|
39
|
+
rendered_marks = marks.keys.map { |m| marks[m.to_s].render(data[m.to_sym]) }
|
40
|
+
@context.call("function(marks, options) { const rendered_marks = marks.map((m) => eval(m)); return Plot.plot({ marks: rendered_marks, ...options }).outerHTML.toString() }", rendered_marks, options)
|
41
|
+
end
|
42
|
+
|
43
|
+
require "plot/plot"
|
44
|
+
require "plot/mark"
|
45
|
+
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: plot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Reese Armstrong
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-10-10 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: An unofficial DSL for making charts with Observable Plot. You define
|
14
|
+
plot definitions with the DSL that create full charts when data is added. This gem
|
15
|
+
relies upon the installation of the Bun JavaScript runtime.
|
16
|
+
email: me@reeseric.ci
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/js/bun_runner.js
|
22
|
+
- lib/js/context.js
|
23
|
+
- lib/plot.rb
|
24
|
+
- lib/plot/mark.rb
|
25
|
+
- lib/plot/plot.rb
|
26
|
+
homepage: https://sr.ht/~reesericci/plot
|
27
|
+
licenses:
|
28
|
+
- ISC
|
29
|
+
metadata: {}
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubygems_version: 3.3.7
|
46
|
+
signing_key:
|
47
|
+
specification_version: 4
|
48
|
+
summary: DSL for making charts with Observable Plot
|
49
|
+
test_files: []
|