rubyduino 0.1.1 → 0.1.2
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 +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/rubyduino/spinel.rb +1 -1
- data/lib/rubyduino/version.rb +1 -1
- data/vendor/spinel/Makefile +29 -1
- data/vendor/spinel/spinel_codegen.rb +113 -5
- data/vendor/spinel/test/file_class_methods_int_recv.rb +20 -0
- data/vendor/spinel/test/file_class_methods_int_recv.rb.expected +3 -0
- data/vendor/spinel/test/float_array_sort.rb +18 -0
- data/vendor/spinel/test/float_array_sort.rb.expected +8 -0
- data/vendor/spinel/test/int_array_replace_expr.rb +23 -0
- data/vendor/spinel/test/int_array_replace_expr.rb.expected +7 -0
- data/vendor/spinel/test/integer_literal_no_int32_overflow.rb +29 -0
- data/vendor/spinel/test/integer_literal_no_int32_overflow.rb.expected +5 -0
- data/vendor/spinel/test/obj_class_returns_string.rb +24 -0
- data/vendor/spinel/test/obj_class_returns_string.rb.expected +2 -0
- metadata +11 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 06e43dd1d4e9f5f4d9dbfda78f6954733999175a658f50b5d76186e6c51fc544
|
|
4
|
+
data.tar.gz: 62a7ba189c79f9741001a6724af58026c7870aaa9da5775dcf54c824afcf53d3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9a83433f8069a0e13757f47666c6913307185d66f388eb014fa68bc54a9afd0117e4c7155bf2f8199ffa5a73c4e7de415096f8cdce2a0965f4679cd567cbf7a1
|
|
7
|
+
data.tar.gz: deb4d7cc643e4d93c172a525677fb7944fbc6fb2bab93fe2b48f7893ca2e0886153879fedd42ee7bf06605e4dc0ac5413cb16c767bd59a0ede37cde188dbf0c4
|
data/CHANGELOG.md
CHANGED
data/lib/rubyduino/spinel.rb
CHANGED
data/lib/rubyduino/version.rb
CHANGED
data/vendor/spinel/Makefile
CHANGED
|
@@ -122,7 +122,7 @@ PRISM_LIB = build/libprism.a
|
|
|
122
122
|
CODEGEN_STAMP := build/stamps/spinel_codegen.rb.stamp
|
|
123
123
|
PARSE_STAMP := build/stamps/spinel_parse.c.stamp
|
|
124
124
|
|
|
125
|
-
.PHONY: all parse bootstrap codegen test retest clean-test-results regen-expected bench clean install uninstall deps
|
|
125
|
+
.PHONY: all parse bootstrap codegen test retest clean-test-results regen-expected bench optcarrot clean install uninstall deps
|
|
126
126
|
|
|
127
127
|
all: parse regexp spinel_codegen$(EXE)
|
|
128
128
|
|
|
@@ -378,6 +378,34 @@ bench: spinel_parse$(EXE) $(SP_RT_LIB) spinel_codegen$(EXE)
|
|
|
378
378
|
echo "Benchmarks: $$pass pass, $$fail fail, $$err error, $$skip skip"; \
|
|
379
379
|
if [ $$fail -ne 0 ] || [ $$err -ne 0 ]; then exit 1; fi
|
|
380
380
|
|
|
381
|
+
# ---- Optcarrot integration test ----
|
|
382
|
+
#
|
|
383
|
+
# End-to-end pipeline: clone optcarrot's `experiment/spinel` branch,
|
|
384
|
+
# pack `lib/optcarrot/*.rb` into a single Ruby file via the upstream
|
|
385
|
+
# `tools/pack-for-spinel.rb`, compile through spinel, run the
|
|
386
|
+
# resulting binary against `examples/Lan_Master.nes`, and verify the
|
|
387
|
+
# output contains `fps: <num>` and `checksum: 59662` (the canonical
|
|
388
|
+
# 180-frame checksum for `--benchmark`).
|
|
389
|
+
|
|
390
|
+
OPTCARROT_DIR := build/optcarrot
|
|
391
|
+
OPTCARROT_REPO := https://github.com/mame/optcarrot.git
|
|
392
|
+
OPTCARROT_BRANCH := experiment/spinel
|
|
393
|
+
|
|
394
|
+
optcarrot: spinel_parse$(EXE) $(SP_RT_LIB) spinel_codegen$(EXE)
|
|
395
|
+
@if [ ! -d $(OPTCARROT_DIR) ]; then \
|
|
396
|
+
git clone --depth=1 --branch=$(OPTCARROT_BRANCH) $(OPTCARROT_REPO) $(OPTCARROT_DIR); \
|
|
397
|
+
fi
|
|
398
|
+
@ruby $(OPTCARROT_DIR)/tools/pack-for-spinel.rb > build/optcarrot-single.rb
|
|
399
|
+
@./spinel build/optcarrot-single.rb -o build/optcarrot-single
|
|
400
|
+
@out=$$($(TIMEOUT60) ./build/optcarrot-single 2>&1); \
|
|
401
|
+
echo "$$out"; \
|
|
402
|
+
if echo "$$out" | grep -qE "^fps: [0-9.]+$$" && echo "$$out" | grep -q "^checksum: 59662$$"; then \
|
|
403
|
+
echo "Optcarrot: OK"; \
|
|
404
|
+
else \
|
|
405
|
+
echo "Optcarrot: FAIL — expected 'fps: <num>' and 'checksum: 59662'"; \
|
|
406
|
+
exit 1; \
|
|
407
|
+
fi
|
|
408
|
+
|
|
381
409
|
# ---- Install ----
|
|
382
410
|
|
|
383
411
|
PREFIX ?= /usr/local
|
|
@@ -2934,6 +2934,18 @@ class Compiler
|
|
|
2934
2934
|
end
|
|
2935
2935
|
end
|
|
2936
2936
|
|
|
2937
|
+
# `<obj>.class` returns the class name as a string (Spinel
|
|
2938
|
+
# collapses Class/Module objects to their textual name; the
|
|
2939
|
+
# only consumers in practice are interpolation
|
|
2940
|
+
# `"#<#{self.class}>"` and `.to_s.split` chains, both of
|
|
2941
|
+
# which work fine on a plain string).
|
|
2942
|
+
if recv >= 0 && mname == "class"
|
|
2943
|
+
rt = infer_type(recv)
|
|
2944
|
+
if is_obj_type(rt) == 1
|
|
2945
|
+
return "string"
|
|
2946
|
+
end
|
|
2947
|
+
end
|
|
2948
|
+
|
|
2937
2949
|
# `recv.__sp_ieval_<N>(...)`: the rewritten form of an
|
|
2938
2950
|
# `recv.instance_eval { ... }` call. v1 only fired on top-level call
|
|
2939
2951
|
# sites, where the call's value was always discarded — so its return
|
|
@@ -3994,6 +4006,16 @@ class Compiler
|
|
|
3994
4006
|
end
|
|
3995
4007
|
return "int_array"
|
|
3996
4008
|
end
|
|
4009
|
+
# `replace(other)` returns the receiver, not a fresh array;
|
|
4010
|
+
# the inferred result must therefore preserve the receiver's
|
|
4011
|
+
# array type so that an expression-form `c = a.replace(b)`
|
|
4012
|
+
# still tags `c` as `int_array` (or whatever `a` is) rather
|
|
4013
|
+
# than falling through to `int`.
|
|
4014
|
+
if mname == "replace"
|
|
4015
|
+
if recv >= 0
|
|
4016
|
+
return infer_type(recv)
|
|
4017
|
+
end
|
|
4018
|
+
end
|
|
3997
4019
|
if mname == "pop"
|
|
3998
4020
|
if recv >= 0
|
|
3999
4021
|
rt = infer_type(recv)
|
|
@@ -4643,7 +4665,7 @@ class Compiler
|
|
|
4643
4665
|
if mname == "read" || mname == "binread"
|
|
4644
4666
|
return "string"
|
|
4645
4667
|
end
|
|
4646
|
-
if mname == "exist?"
|
|
4668
|
+
if mname == "exist?" || mname == "readable?"
|
|
4647
4669
|
return "bool"
|
|
4648
4670
|
end
|
|
4649
4671
|
if mname == "join"
|
|
@@ -17819,6 +17841,14 @@ class Compiler
|
|
|
17819
17841
|
|
|
17820
17842
|
# ---- Forward declarations ----
|
|
17821
17843
|
def emit_forward_decls
|
|
17844
|
+
# ARGV (sp_argv) is referenced from any function that uses
|
|
17845
|
+
# `ARGV.length` / `ARGV[i]`, so the declaration has to precede
|
|
17846
|
+
# all function bodies — not just main()'s. emit_main keeps the
|
|
17847
|
+
# runtime initialization (`sp_argv.len = argc - 1; ...`) where
|
|
17848
|
+
# main() can fill it in from `argc` / `argv`.
|
|
17849
|
+
emit_raw("typedef struct{const char**data;mrb_int len;}sp_Argv;")
|
|
17850
|
+
emit_raw("static sp_Argv sp_argv;")
|
|
17851
|
+
emit_raw("")
|
|
17822
17852
|
# Emit block helper functions accumulated during collection
|
|
17823
17853
|
if @block_funcs != ""
|
|
17824
17854
|
emit_raw(@block_funcs)
|
|
@@ -20806,9 +20836,6 @@ class Compiler
|
|
|
20806
20836
|
|
|
20807
20837
|
def emit_main
|
|
20808
20838
|
stmts = get_body_stmts(@root_id)
|
|
20809
|
-
emit_raw("typedef struct{const char**data;mrb_int len;}sp_Argv;")
|
|
20810
|
-
emit_raw("static sp_Argv sp_argv;")
|
|
20811
|
-
emit_raw("")
|
|
20812
20839
|
emit_raw("int main(int argc,char**argv){")
|
|
20813
20840
|
emit_raw(" sp_argv.len=argc-1;sp_argv.data=(const char**)malloc(sizeof(const char*)*(argc>1?argc-1:1));{int _i;for(_i=0;_i<sp_argv.len;_i++)sp_argv.data[_i]=sp_str_dup_external(argv[_i+1]);}")
|
|
20814
20841
|
if @needs_rand == 1
|
|
@@ -21303,7 +21330,16 @@ class Compiler
|
|
|
21303
21330
|
exit(1)
|
|
21304
21331
|
end
|
|
21305
21332
|
if t == "IntegerNode"
|
|
21306
|
-
|
|
21333
|
+
# Suffix with `LL` so the literal is `long long` rather than
|
|
21334
|
+
# `int` in the emitted C. Without it, an expression of int
|
|
21335
|
+
# literals whose product exceeds int32 (e.g. APU mixer
|
|
21336
|
+
# constant `24329 * 256 * 500 = 3,114,112,000`) overflows
|
|
21337
|
+
# at constant-folding time and the C compiler emits a wrong
|
|
21338
|
+
# value. Plain literals at runtime sites get implicitly
|
|
21339
|
+
# promoted to mrb_int (= long long) on assignment, but
|
|
21340
|
+
# constant-init expressions are evaluated by the C compiler
|
|
21341
|
+
# using the literals' declared type.
|
|
21342
|
+
return @nd_value[nid].to_s + "LL"
|
|
21307
21343
|
end
|
|
21308
21344
|
if t == "FloatNode"
|
|
21309
21345
|
return @nd_content[nid]
|
|
@@ -26285,6 +26321,37 @@ class Compiler
|
|
|
26285
26321
|
end
|
|
26286
26322
|
return "sp_IntArray_sort(" + rc + ")"
|
|
26287
26323
|
end
|
|
26324
|
+
# `pack("C*")` — the only format Spinel implements: each
|
|
26325
|
+
# int element is written as a byte into a freshly allocated
|
|
26326
|
+
# NUL-terminated string. Sufficient for the optcarrot save-
|
|
26327
|
+
# RAM `@wrk.pack("C*")` shape and the symmetric inverse of
|
|
26328
|
+
# `String#bytes` we already support. Other format strings
|
|
26329
|
+
# fall through to the unresolved-call warning.
|
|
26330
|
+
if mname == "pack" && recv_type == "int_array"
|
|
26331
|
+
args_id = @nd_arguments[nid]
|
|
26332
|
+
if args_id >= 0
|
|
26333
|
+
a_pk = get_args(args_id)
|
|
26334
|
+
if a_pk.length == 1 && @nd_type[a_pk[0]] == "StringNode" && @nd_content[a_pk[0]] == "C*"
|
|
26335
|
+
tmp = new_temp
|
|
26336
|
+
ntmp = new_temp
|
|
26337
|
+
itmp = new_temp
|
|
26338
|
+
emit(" mrb_int " + ntmp + " = sp_IntArray_length(" + rc + ");")
|
|
26339
|
+
emit(" char *" + tmp + " = sp_str_alloc(" + ntmp + ");")
|
|
26340
|
+
emit(" for (mrb_int " + itmp + " = 0; " + itmp + " < " + ntmp + "; " + itmp + "++) " + tmp + "[" + itmp + "] = (char)sp_IntArray_get(" + rc + ", " + itmp + ");")
|
|
26341
|
+
emit(" " + tmp + "[" + ntmp + "] = 0;")
|
|
26342
|
+
return tmp
|
|
26343
|
+
end
|
|
26344
|
+
end
|
|
26345
|
+
end
|
|
26346
|
+
# `replace(other)` in expression position: the stmt-form
|
|
26347
|
+
# arm in compile_*_stmt only fires when the call's value is
|
|
26348
|
+
# discarded; in expression position (e.g. last stmt of a
|
|
26349
|
+
# method body, or rvalue of an assignment) we still need to
|
|
26350
|
+
# emit the side effect *and* yield the receiver as the
|
|
26351
|
+
# value. Use the comma operator so the result is `rc`.
|
|
26352
|
+
if mname == "replace" && recv_type == "int_array"
|
|
26353
|
+
return "(sp_IntArray_replace(" + rc + ", " + compile_arg0(nid) + "), " + rc + ")"
|
|
26354
|
+
end
|
|
26288
26355
|
# take_while / drop_while: block-driven prefix scan. take_while
|
|
26289
26356
|
# collects elements from the front while the block stays truthy;
|
|
26290
26357
|
# drop_while skips them and returns the rest. Mirrors the
|
|
@@ -26539,6 +26606,14 @@ class Compiler
|
|
|
26539
26606
|
if mname == "difference"
|
|
26540
26607
|
return "sp_FloatArray_difference(" + rc + ", " + compile_arg0(nid) + ")"
|
|
26541
26608
|
end
|
|
26609
|
+
if mname == "sort"
|
|
26610
|
+
# Non-bang: yield a fresh sorted copy. Mirror the
|
|
26611
|
+
# `sp_FloatArray_shuffle` pattern (new + replace) so the
|
|
26612
|
+
# source array is left untouched.
|
|
26613
|
+
tmp = new_temp
|
|
26614
|
+
emit(" sp_FloatArray *" + tmp + " = sp_FloatArray_new(); sp_FloatArray_replace(" + tmp + ", " + rc + "); sp_FloatArray_sort_bang(" + tmp + ");")
|
|
26615
|
+
return tmp
|
|
26616
|
+
end
|
|
26542
26617
|
end
|
|
26543
26618
|
if is_ptr_array_type(recv_type) == 1
|
|
26544
26619
|
elem_type = ptr_array_elem_type(recv_type)
|
|
@@ -27529,9 +27604,32 @@ class Compiler
|
|
|
27529
27604
|
if mname == "exist?"
|
|
27530
27605
|
return "sp_file_exist(" + compile_arg0(nid) + ")"
|
|
27531
27606
|
end
|
|
27607
|
+
if mname == "readable?"
|
|
27608
|
+
# Reuse the exist check: on every platform Spinel
|
|
27609
|
+
# targets, a fopen-able file is also readable from
|
|
27610
|
+
# the same process. Distinguishing the two would
|
|
27611
|
+
# need access(2), which isn't worth a runtime fn for
|
|
27612
|
+
# the dead-code optcarrot battery-save path that
|
|
27613
|
+
# surfaced this.
|
|
27614
|
+
return "sp_file_exist(" + compile_arg0(nid) + ")"
|
|
27615
|
+
end
|
|
27532
27616
|
if mname == "delete"
|
|
27533
27617
|
return "(sp_file_delete(" + compile_arg0(nid) + "), 0)"
|
|
27534
27618
|
end
|
|
27619
|
+
if mname == "binwrite"
|
|
27620
|
+
# NOTE: `sp_file_write` uses fputs, so an embedded NUL
|
|
27621
|
+
# in the payload truncates the write — fine for the
|
|
27622
|
+
# optcarrot save-RAM dead-code path that surfaced
|
|
27623
|
+
# this, not safe for general binary use.
|
|
27624
|
+
args_id_bw = @nd_arguments[nid]
|
|
27625
|
+
if args_id_bw >= 0
|
|
27626
|
+
a_bw = get_args(args_id_bw)
|
|
27627
|
+
if a_bw.length >= 2
|
|
27628
|
+
return "(sp_file_write(" + compile_expr(a_bw[0]) + ", " + compile_expr(a_bw[1]) + "), 0)"
|
|
27629
|
+
end
|
|
27630
|
+
end
|
|
27631
|
+
return "0"
|
|
27632
|
+
end
|
|
27535
27633
|
if mname == "join"
|
|
27536
27634
|
args_id = @nd_arguments[nid]
|
|
27537
27635
|
if args_id >= 0
|
|
@@ -27864,6 +27962,16 @@ class Compiler
|
|
|
27864
27962
|
if @cls_is_value_type[ci] == 1
|
|
27865
27963
|
arrow = "."
|
|
27866
27964
|
end
|
|
27965
|
+
# `<obj>.class` — collapse to the class name as a string
|
|
27966
|
+
# literal. Spinel doesn't allocate runtime Class objects,
|
|
27967
|
+
# but the typical consumers (interpolation in inspect,
|
|
27968
|
+
# `.to_s.split("::").last` shape) all treat the result as
|
|
27969
|
+
# a string. Underscore-flattened nested module names
|
|
27970
|
+
# (`Optcarrot_NES`) render as-is rather than the original
|
|
27971
|
+
# `Optcarrot::NES` form; the loss is cosmetic.
|
|
27972
|
+
if mname == "class"
|
|
27973
|
+
return c_string_literal(cname)
|
|
27974
|
+
end
|
|
27867
27975
|
# attr_reader
|
|
27868
27976
|
readers = @cls_attr_readers[ci].split(";")
|
|
27869
27977
|
j = 0
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# `File.readable?` and `File.binwrite` — class-method stubs in
|
|
2
|
+
# the `rcname == "File"` dispatch block, plus `IntArray#pack("C*")`
|
|
3
|
+
# which is the symmetric inverse of `String#bytes`.
|
|
4
|
+
#
|
|
5
|
+
# Surfaced via optcarrot's battery-save dead code path:
|
|
6
|
+
# `return unless File.readable?(sav)` and
|
|
7
|
+
# `File.binwrite(sav, @wrk.pack("C*"))`.
|
|
8
|
+
#
|
|
9
|
+
# `readable?` reuses the exist check (close enough on POSIX).
|
|
10
|
+
# `binwrite` reuses `sp_file_write` — fputs-based, so embedded
|
|
11
|
+
# NULs truncate; acceptable for the NUL-free use sites that
|
|
12
|
+
# exist in practice.
|
|
13
|
+
|
|
14
|
+
path = "/tmp/spinel_file_class_test"
|
|
15
|
+
|
|
16
|
+
File.binwrite(path, [72, 105, 33].pack("C*")) # "Hi!"
|
|
17
|
+
puts File.readable?(path)
|
|
18
|
+
puts File.read(path)
|
|
19
|
+
File.delete(path)
|
|
20
|
+
puts File.exist?(path)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# `Array#sort` (non-bang) on a float array. Surfaced via
|
|
2
|
+
# optcarrot's `@fps_history.sort[(@fps_history.length * 0.05).floor]`
|
|
3
|
+
# p95 calculation. Mirrors the existing int_array sort path —
|
|
4
|
+
# yields a fresh sorted array; the source stays untouched.
|
|
5
|
+
|
|
6
|
+
a = [3.5, 1.25, 2.0, 0.75, 4.125]
|
|
7
|
+
b = a.sort
|
|
8
|
+
puts b.length
|
|
9
|
+
|
|
10
|
+
i = 0
|
|
11
|
+
while i < b.length
|
|
12
|
+
puts b[i]
|
|
13
|
+
i = i + 1
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Source unchanged.
|
|
17
|
+
puts a[0]
|
|
18
|
+
puts a[1]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# `Array#replace` in *expression* position on an int_array.
|
|
2
|
+
# The stmt-form arm has long supported this; the expr-form was
|
|
3
|
+
# missing — unresolved-call warning + literal `0` emitted.
|
|
4
|
+
# Surfaced via optcarrot's `def load_battery; ...; @wrk.replace(sav.bytes); end`,
|
|
5
|
+
# where the call sits at the tail of the method (its value is
|
|
6
|
+
# the implicit return).
|
|
7
|
+
|
|
8
|
+
a = [1, 2, 3]
|
|
9
|
+
b = [10, 20, 30, 40]
|
|
10
|
+
|
|
11
|
+
# Expression position: assigned. Should yield the (mutated) `a`.
|
|
12
|
+
c = a.replace(b)
|
|
13
|
+
|
|
14
|
+
# `a` mutated in place
|
|
15
|
+
puts a[0]
|
|
16
|
+
puts a[1]
|
|
17
|
+
puts a[2]
|
|
18
|
+
puts a[3]
|
|
19
|
+
puts a.length
|
|
20
|
+
|
|
21
|
+
# `c` is the same array (replace returns the receiver)
|
|
22
|
+
puts c[0]
|
|
23
|
+
puts c.length
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Spinel's integers are mrb_int (long long); Ruby integers don't
|
|
2
|
+
# overflow in the same range. But emitting a plain `24329 * 256 *
|
|
3
|
+
# 500` in C lets the C compiler fold the constant using `int`
|
|
4
|
+
# arithmetic, overflowing at 3,114,112,000 to a wrong negative
|
|
5
|
+
# result on 32-bit-int platforms.
|
|
6
|
+
#
|
|
7
|
+
# Surfaced via optcarrot's `APU::Mixer::TND_1 = 100 * 24329 * 256
|
|
8
|
+
# / 500`-shaped constant expressions whose intermediate products
|
|
9
|
+
# clear int32 max. Same hazard for any constant-init expression
|
|
10
|
+
# of integer literals whose folded result exceeds INT_MAX.
|
|
11
|
+
#
|
|
12
|
+
# Fix: emit the `LL` suffix on every IntegerNode literal so
|
|
13
|
+
# operands carry `long long` type at the C level. Runtime
|
|
14
|
+
# expressions assigned to `mrb_int` slots already promoted
|
|
15
|
+
# implicitly; only constant-init contexts (where the C compiler
|
|
16
|
+
# folds before any assignment) saw the overflow.
|
|
17
|
+
|
|
18
|
+
# Each chain straddles int32: max 2^31 - 1 = 2,147,483,647.
|
|
19
|
+
A = 24329 * 256 * 500 # 3,114,112,000
|
|
20
|
+
B = 100000 * 100000 # 10,000,000,000
|
|
21
|
+
C = 65535 * 65535 # 4,294,836,225
|
|
22
|
+
D = 2 ** 40 # 1,099,511,627,776
|
|
23
|
+
E = 1_000_000_000 + 1_000_000_000 # 2,000,000,000 — sum overflow
|
|
24
|
+
|
|
25
|
+
puts A
|
|
26
|
+
puts B
|
|
27
|
+
puts C
|
|
28
|
+
puts D
|
|
29
|
+
puts E
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# `<user_obj>.class` collapses to the class name as a string.
|
|
2
|
+
# Spinel doesn't allocate runtime Class objects, so the only
|
|
3
|
+
# coherent representation for `obj.class` is the textual name.
|
|
4
|
+
# The two real-world consumers in optcarrot are:
|
|
5
|
+
# 1. `"#<#{ self.class }>"`-style interpolation in `inspect`
|
|
6
|
+
# 2. `self.class.to_s.split("::").last`-style introspection
|
|
7
|
+
# Both work fine if `.class` simply yields the class name as a
|
|
8
|
+
# string (the second loses the `::` namespace because Spinel
|
|
9
|
+
# flattens nested modules with `_`, but that's a cosmetic loss).
|
|
10
|
+
|
|
11
|
+
class Foo
|
|
12
|
+
def to_s
|
|
13
|
+
"<" + self.class + ">"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class Bar
|
|
18
|
+
def label
|
|
19
|
+
self.class.to_s
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
puts Foo.new.to_s # => <Foo>
|
|
24
|
+
puts Bar.new.label # => Bar
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubyduino
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joseph Schito
|
|
@@ -345,6 +345,10 @@ files:
|
|
|
345
345
|
- vendor/spinel/test/fiber_yield_across_method_call.rb.expected
|
|
346
346
|
- vendor/spinel/test/file_basename_gc.rb
|
|
347
347
|
- vendor/spinel/test/file_basename_gc.rb.expected
|
|
348
|
+
- vendor/spinel/test/file_class_methods_int_recv.rb
|
|
349
|
+
- vendor/spinel/test/file_class_methods_int_recv.rb.expected
|
|
350
|
+
- vendor/spinel/test/float_array_sort.rb
|
|
351
|
+
- vendor/spinel/test/float_array_sort.rb.expected
|
|
348
352
|
- vendor/spinel/test/forward_call_class_method_inherited_init.rb
|
|
349
353
|
- vendor/spinel/test/forward_call_class_method_inherited_init.rb.expected
|
|
350
354
|
- vendor/spinel/test/forward_call_class_method_inherited_init_int_array.rb
|
|
@@ -407,6 +411,8 @@ files:
|
|
|
407
411
|
- vendor/spinel/test/inspect.rb.expected
|
|
408
412
|
- vendor/spinel/test/instance_eval_trampoline.rb
|
|
409
413
|
- vendor/spinel/test/instance_eval_trampoline.rb.expected
|
|
414
|
+
- vendor/spinel/test/int_array_replace_expr.rb
|
|
415
|
+
- vendor/spinel/test/int_array_replace_expr.rb.expected
|
|
410
416
|
- vendor/spinel/test/int_bracket_skip_sym_idx.rb
|
|
411
417
|
- vendor/spinel/test/int_bracket_skip_sym_idx.rb.expected
|
|
412
418
|
- vendor/spinel/test/int_keyed_hash_lookup_as_array.rb
|
|
@@ -417,6 +423,8 @@ files:
|
|
|
417
423
|
- vendor/spinel/test/integer_div.rb.expected
|
|
418
424
|
- vendor/spinel/test/integer_div_by_zero.rb
|
|
419
425
|
- vendor/spinel/test/integer_div_by_zero.rb.expected
|
|
426
|
+
- vendor/spinel/test/integer_literal_no_int32_overflow.rb
|
|
427
|
+
- vendor/spinel/test/integer_literal_no_int32_overflow.rb.expected
|
|
420
428
|
- vendor/spinel/test/interp_method_widening.rb
|
|
421
429
|
- vendor/spinel/test/interp_method_widening.rb.expected
|
|
422
430
|
- vendor/spinel/test/interp_symbol.rb
|
|
@@ -560,6 +568,8 @@ files:
|
|
|
560
568
|
- vendor/spinel/test/nullable.rb.expected
|
|
561
569
|
- vendor/spinel/test/obj_array.rb
|
|
562
570
|
- vendor/spinel/test/obj_array.rb.expected
|
|
571
|
+
- vendor/spinel/test/obj_class_returns_string.rb
|
|
572
|
+
- vendor/spinel/test/obj_class_returns_string.rb.expected
|
|
563
573
|
- vendor/spinel/test/object_new_sentinel.rb
|
|
564
574
|
- vendor/spinel/test/object_new_sentinel.rb.expected
|
|
565
575
|
- vendor/spinel/test/object_truthy.rb
|