node-marshal 0.2.1 → 0.2.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/COPYING +23 -23
- data/README.rdoc +56 -49
- data/bin/noderbc +63 -63
- data/bin/noderbc.bat +0 -0
- data/ext/node-marshal/base85r.c +194 -194
- data/ext/node-marshal/extconf.rb +2 -2
- data/ext/node-marshal/node193.h +321 -321
- data/ext/node-marshal/node220.h +347 -347
- data/ext/node-marshal/node230.h +361 -361
- data/ext/node-marshal/nodedump.c +2356 -2296
- data/ext/node-marshal/nodedump.h +60 -60
- data/ext/node-marshal/nodeinfo.c +619 -615
- data/lib/node-marshal.rb +227 -227
- data/test/lifegame.rb +145 -145
- data/test/test_base.rb +226 -226
- data/test/test_complex.rb +136 -136
- data/test/test_lifegame.rb +68 -68
- data/test/test_namedarg.rb +54 -0
- data/test/test_obfuscator.rb +36 -36
- data/test/test_qcall.rb +52 -52
- data/test/tinytet.rb +79 -79
- metadata +4 -3
data/test/test_obfuscator.rb
CHANGED
@@ -1,36 +1,36 @@
|
|
1
|
-
require_relative '../lib/node-marshal.rb'
|
2
|
-
require 'test/unit'
|
3
|
-
|
4
|
-
# Test node-marshal obfuscator abilities
|
5
|
-
class TestObfuscator < Test::Unit::TestCase
|
6
|
-
def test_sym_replace
|
7
|
-
# Create the node and find all new symbols
|
8
|
-
symlog = SymbolsLogger.new
|
9
|
-
node = NodeMarshal.new(:srcfile, 'lifegame.rb')
|
10
|
-
our_symbols = symlog.new_symbols.map(&:to_s)
|
11
|
-
node.to_hash
|
12
|
-
# Try to exclude symbols used in attr_reader and attr_writer constructions
|
13
|
-
our_symbols = node.get_safe_symbols(our_symbols)
|
14
|
-
# Prepare hash table for replacement
|
15
|
-
reptbl = node.get_aliases_table(our_symbols)
|
16
|
-
life_game_name = reptbl["LifeGame"]
|
17
|
-
grid_name = reptbl["Grid"]
|
18
|
-
make_step_name = reptbl["make_step!"].to_sym
|
19
|
-
cfg_glider_gun_name = reptbl["cfg_glider_gun!"].to_sym
|
20
|
-
# Replace symbols
|
21
|
-
puts "----- Symbols replacement table"
|
22
|
-
puts reptbl.to_s
|
23
|
-
puts "-------------------------------"
|
24
|
-
node.replace_symbols(reptbl)
|
25
|
-
# Rebuild node, save it to the file and reload it
|
26
|
-
node = node.rebuild
|
27
|
-
File.open('life.bin', 'wb') {|fp| fp << node.to_bin};
|
28
|
-
node.compile.eval
|
29
|
-
# Execute the node
|
30
|
-
grid_class = Object.const_get(life_game_name).const_get(grid_name)
|
31
|
-
g = grid_class.new(25, 80)
|
32
|
-
g.send(cfg_glider_gun_name)
|
33
|
-
75.times {g.send(make_step_name)}
|
34
|
-
puts g.to_ascii
|
35
|
-
end
|
36
|
-
end
|
1
|
+
require_relative '../lib/node-marshal.rb'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
# Test node-marshal obfuscator abilities
|
5
|
+
class TestObfuscator < Test::Unit::TestCase
|
6
|
+
def test_sym_replace
|
7
|
+
# Create the node and find all new symbols
|
8
|
+
symlog = SymbolsLogger.new
|
9
|
+
node = NodeMarshal.new(:srcfile, 'lifegame.rb')
|
10
|
+
our_symbols = symlog.new_symbols.map(&:to_s)
|
11
|
+
node.to_hash
|
12
|
+
# Try to exclude symbols used in attr_reader and attr_writer constructions
|
13
|
+
our_symbols = node.get_safe_symbols(our_symbols)
|
14
|
+
# Prepare hash table for replacement
|
15
|
+
reptbl = node.get_aliases_table(our_symbols)
|
16
|
+
life_game_name = reptbl["LifeGame"]
|
17
|
+
grid_name = reptbl["Grid"]
|
18
|
+
make_step_name = reptbl["make_step!"].to_sym
|
19
|
+
cfg_glider_gun_name = reptbl["cfg_glider_gun!"].to_sym
|
20
|
+
# Replace symbols
|
21
|
+
puts "----- Symbols replacement table"
|
22
|
+
puts reptbl.to_s
|
23
|
+
puts "-------------------------------"
|
24
|
+
node.replace_symbols(reptbl)
|
25
|
+
# Rebuild node, save it to the file and reload it
|
26
|
+
node = node.rebuild
|
27
|
+
File.open('life.bin', 'wb') {|fp| fp << node.to_bin};
|
28
|
+
node.compile.eval
|
29
|
+
# Execute the node
|
30
|
+
grid_class = Object.const_get(life_game_name).const_get(grid_name)
|
31
|
+
g = grid_class.new(25, 80)
|
32
|
+
g.send(cfg_glider_gun_name)
|
33
|
+
75.times {g.send(make_step_name)}
|
34
|
+
puts g.to_ascii
|
35
|
+
end
|
36
|
+
end
|
data/test/test_qcall.rb
CHANGED
@@ -1,52 +1,52 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
require_relative '../lib/node-marshal.rb'
|
3
|
-
require 'test/unit'
|
4
|
-
|
5
|
-
|
6
|
-
# This unit tests Ruby 2.3 &. safe navigation operator
|
7
|
-
class TestQCALL < Test::Unit::TestCase
|
8
|
-
def test_qcall
|
9
|
-
qcall_program = %q{
|
10
|
-
class Account
|
11
|
-
def initialize(owner_name, owner_address)
|
12
|
-
@owner_name = owner_name
|
13
|
-
@owner_info = (owner_address.nil?) ? nil : OwnerInfo.new(owner_address);
|
14
|
-
end
|
15
|
-
def owner_name
|
16
|
-
@owner_name
|
17
|
-
end
|
18
|
-
def owner_info
|
19
|
-
@owner_info
|
20
|
-
end
|
21
|
-
end
|
22
|
-
class OwnerInfo
|
23
|
-
def initialize(address)
|
24
|
-
@address = address
|
25
|
-
end
|
26
|
-
def address
|
27
|
-
@address
|
28
|
-
end
|
29
|
-
end
|
30
|
-
a = Account.new("Owner", "Moscow");
|
31
|
-
puts "'#{a&.owner_name}'"
|
32
|
-
puts "'#{a&.owner_info&.address}'"
|
33
|
-
b = Account.new("Owner", nil);
|
34
|
-
puts "'#{b&.owner_name}'"
|
35
|
-
puts "'#{b&.owner_info&.address}'"
|
36
|
-
[a&.owner_name, a&.owner_info&.address, b&.owner_name, b&.owner_info&.address]
|
37
|
-
}
|
38
|
-
ver = RUBY_VERSION
|
39
|
-
ver = (ver[0] + ver[2] + ver[4]).to_i
|
40
|
-
if ver >= 230
|
41
|
-
node = NodeMarshal.new(:srcmemory, qcall_program)
|
42
|
-
node.show_offsets = true
|
43
|
-
bindump = node.to_bin
|
44
|
-
node = NodeMarshal.new(:binmemory, bindump)
|
45
|
-
res_node = node.compile.eval
|
46
|
-
res_text = eval(qcall_program)
|
47
|
-
assert_equal(res_text, res_node)
|
48
|
-
else
|
49
|
-
assert_equal(false, true, "Ruby 2.3 or higher is required for &. operator test")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
1
|
+
# encoding: UTF-8
|
2
|
+
require_relative '../lib/node-marshal.rb'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
|
6
|
+
# This unit tests Ruby 2.3 &. safe navigation operator
|
7
|
+
class TestQCALL < Test::Unit::TestCase
|
8
|
+
def test_qcall
|
9
|
+
qcall_program = %q{
|
10
|
+
class Account
|
11
|
+
def initialize(owner_name, owner_address)
|
12
|
+
@owner_name = owner_name
|
13
|
+
@owner_info = (owner_address.nil?) ? nil : OwnerInfo.new(owner_address);
|
14
|
+
end
|
15
|
+
def owner_name
|
16
|
+
@owner_name
|
17
|
+
end
|
18
|
+
def owner_info
|
19
|
+
@owner_info
|
20
|
+
end
|
21
|
+
end
|
22
|
+
class OwnerInfo
|
23
|
+
def initialize(address)
|
24
|
+
@address = address
|
25
|
+
end
|
26
|
+
def address
|
27
|
+
@address
|
28
|
+
end
|
29
|
+
end
|
30
|
+
a = Account.new("Owner", "Moscow");
|
31
|
+
puts "'#{a&.owner_name}'"
|
32
|
+
puts "'#{a&.owner_info&.address}'"
|
33
|
+
b = Account.new("Owner", nil);
|
34
|
+
puts "'#{b&.owner_name}'"
|
35
|
+
puts "'#{b&.owner_info&.address}'"
|
36
|
+
[a&.owner_name, a&.owner_info&.address, b&.owner_name, b&.owner_info&.address]
|
37
|
+
}
|
38
|
+
ver = RUBY_VERSION
|
39
|
+
ver = (ver[0] + ver[2] + ver[4]).to_i
|
40
|
+
if ver >= 230
|
41
|
+
node = NodeMarshal.new(:srcmemory, qcall_program)
|
42
|
+
node.show_offsets = true
|
43
|
+
bindump = node.to_bin
|
44
|
+
node = NodeMarshal.new(:binmemory, bindump)
|
45
|
+
res_node = node.compile.eval
|
46
|
+
res_text = eval(qcall_program)
|
47
|
+
assert_equal(res_text, res_node)
|
48
|
+
else
|
49
|
+
assert_equal(false, true, "Ruby 2.3 or higher is required for &. operator test")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/test/tinytet.rb
CHANGED
@@ -1,79 +1,79 @@
|
|
1
|
-
#!/usr/bin/ruby
|
2
|
-
# Simple TETRIS game for Ruby 1.9.x that uses CURSES library
|
3
|
-
# (C) 2013 Alexey Voskov
|
4
|
-
require "curses"
|
5
|
-
include Curses
|
6
|
-
# TETRIS figure
|
7
|
-
class Figure
|
8
|
-
attr_accessor :mat, :x, :y, :rot
|
9
|
-
FIGURES = [0x0F00,0x0660,0x0270,0x0170,0x0470,0x0360,0x0C60] # Line, square, T, L, L, Z, Z
|
10
|
-
def initialize
|
11
|
-
fig = FIGURES[rand(6).round]
|
12
|
-
rf = ->bf{Array.new(4) {|y| Array.new(4) {|x| (1 << bf.(x,y)) & fig }}}
|
13
|
-
@mat = [rf.(->x,y{3-x+y*4}), rf.(->x,y{3-y+(3-x)*4}),
|
14
|
-
rf.(->x,y{x+(3-y)*4}), rf.(->x,y{y+x*4})]
|
15
|
-
@x, @y, @rot = 5, 0, 0 # Figure position
|
16
|
-
end
|
17
|
-
def each_pos &block
|
18
|
-
(0..3).each {|y| (0..3).each {|x| block.(y,x) if @mat[@rot][y][x] > 0}}
|
19
|
-
end
|
20
|
-
# Test the possibility of move and move if possible
|
21
|
-
def move!(op, unop, scr)
|
22
|
-
self.each_pos {|y,x| scr.brick!(y+@y,x+@x,GameField::COL_EMPTY) }
|
23
|
-
op.(self)
|
24
|
-
unop.(self) if !(ans = scr.place?self)
|
25
|
-
self.each_pos {|y,x| scr.brick!(y+@y,x+@x,GameField::COL_BRICK) }
|
26
|
-
refresh
|
27
|
-
ans
|
28
|
-
end
|
29
|
-
end
|
30
|
-
# TETRIS game fields
|
31
|
-
class GameField
|
32
|
-
WIDTH, HEIGHT, BRICK_WIDTH, COL_EMPTY, COL_WALL, COL_BRICK = 16, 26, 2, 0, 1, 2
|
33
|
-
def initialize # Initialize and show the game fields
|
34
|
-
@m = Array.new(HEIGHT+2) {[0,0,1,Array.new(WIDTH-6){0},1,0,0].flatten}
|
35
|
-
(2..WIDTH-3).each {|i| @m[HEIGHT-1][i] = COL_WALL}
|
36
|
-
lines!
|
37
|
-
end
|
38
|
-
def brick!(y,x,c) # Show the brick on the screen
|
39
|
-
@m[y][x] = c.to_i
|
40
|
-
return nil if y-3 <= 0
|
41
|
-
setpos(y-3,x*BRICK_WIDTH)
|
42
|
-
addstr([". ", "**", "[]"][c])
|
43
|
-
end
|
44
|
-
def place?(fig) # Check if the figure can be placed
|
45
|
-
fig.each_pos {|y,x| return false if @m[y+fig.y][x+fig.x] > 0}
|
46
|
-
return true
|
47
|
-
end
|
48
|
-
def lines! # Erase full lines from the screen
|
49
|
-
while (ind = @m[0..HEIGHT-2].index {|s| s[3..WIDTH-4].index(COL_EMPTY) == nil}) != nil
|
50
|
-
(ind-1).step(0,-1) {|i| @m[i+1] = @m[i]}
|
51
|
-
@m[0] = @m[HEIGHT+1].dup
|
52
|
-
end
|
53
|
-
(0..HEIGHT-1).each {|y| (2..WIDTH-3).each {|x| brick!(y,x,@m[y][x])}} # Update the screen (field + borders)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
# Initialize the console and program data
|
57
|
-
init_screen; clear; noecho; stdscr.keypad(true)
|
58
|
-
fig, scr, speed = Figure.new, GameField.new, 1
|
59
|
-
# Keyboard control thread
|
60
|
-
keythread = Thread.new { loop {
|
61
|
-
case getch
|
62
|
-
when Key::LEFT then fig.move!(->f{f.x -=1}, ->f{f.x +=1}, scr)
|
63
|
-
when Key::RIGHT then fig.move!(->f{f.x +=1}, ->f{f.x -=1}, scr)
|
64
|
-
when Key::UP then fig.move!(->f{f.rot = (f.rot+1)%4}, ->f{f.rot = (f.rot+3)%4},scr)
|
65
|
-
when Key::DOWN then speed = 0.05 # Delay for fast falling
|
66
|
-
end
|
67
|
-
}}
|
68
|
-
# Game main loop (new figure creation + falling)
|
69
|
-
begin
|
70
|
-
fig, speed = Figure.new, 0.5 # Figure and delay for its normal falling
|
71
|
-
sleep(speed) while fig.move!(->f{f.y +=1}, ->f{f.y -=1}, scr)
|
72
|
-
scr.lines!
|
73
|
-
end until fig.y == 0
|
74
|
-
# Finish the game
|
75
|
-
keythread.kill
|
76
|
-
setpos(GameField::HEIGHT/2,GameField::WIDTH-4)
|
77
|
-
addstr("GAME OVER!")
|
78
|
-
getch
|
79
|
-
close_screen
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# Simple TETRIS game for Ruby 1.9.x that uses CURSES library
|
3
|
+
# (C) 2013 Alexey Voskov
|
4
|
+
require "curses"
|
5
|
+
include Curses
|
6
|
+
# TETRIS figure
|
7
|
+
class Figure
|
8
|
+
attr_accessor :mat, :x, :y, :rot
|
9
|
+
FIGURES = [0x0F00,0x0660,0x0270,0x0170,0x0470,0x0360,0x0C60] # Line, square, T, L, L, Z, Z
|
10
|
+
def initialize
|
11
|
+
fig = FIGURES[rand(6).round]
|
12
|
+
rf = ->bf{Array.new(4) {|y| Array.new(4) {|x| (1 << bf.(x,y)) & fig }}}
|
13
|
+
@mat = [rf.(->x,y{3-x+y*4}), rf.(->x,y{3-y+(3-x)*4}),
|
14
|
+
rf.(->x,y{x+(3-y)*4}), rf.(->x,y{y+x*4})]
|
15
|
+
@x, @y, @rot = 5, 0, 0 # Figure position
|
16
|
+
end
|
17
|
+
def each_pos &block
|
18
|
+
(0..3).each {|y| (0..3).each {|x| block.(y,x) if @mat[@rot][y][x] > 0}}
|
19
|
+
end
|
20
|
+
# Test the possibility of move and move if possible
|
21
|
+
def move!(op, unop, scr)
|
22
|
+
self.each_pos {|y,x| scr.brick!(y+@y,x+@x,GameField::COL_EMPTY) }
|
23
|
+
op.(self)
|
24
|
+
unop.(self) if !(ans = scr.place?self)
|
25
|
+
self.each_pos {|y,x| scr.brick!(y+@y,x+@x,GameField::COL_BRICK) }
|
26
|
+
refresh
|
27
|
+
ans
|
28
|
+
end
|
29
|
+
end
|
30
|
+
# TETRIS game fields
|
31
|
+
class GameField
|
32
|
+
WIDTH, HEIGHT, BRICK_WIDTH, COL_EMPTY, COL_WALL, COL_BRICK = 16, 26, 2, 0, 1, 2
|
33
|
+
def initialize # Initialize and show the game fields
|
34
|
+
@m = Array.new(HEIGHT+2) {[0,0,1,Array.new(WIDTH-6){0},1,0,0].flatten}
|
35
|
+
(2..WIDTH-3).each {|i| @m[HEIGHT-1][i] = COL_WALL}
|
36
|
+
lines!
|
37
|
+
end
|
38
|
+
def brick!(y,x,c) # Show the brick on the screen
|
39
|
+
@m[y][x] = c.to_i
|
40
|
+
return nil if y-3 <= 0
|
41
|
+
setpos(y-3,x*BRICK_WIDTH)
|
42
|
+
addstr([". ", "**", "[]"][c])
|
43
|
+
end
|
44
|
+
def place?(fig) # Check if the figure can be placed
|
45
|
+
fig.each_pos {|y,x| return false if @m[y+fig.y][x+fig.x] > 0}
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
def lines! # Erase full lines from the screen
|
49
|
+
while (ind = @m[0..HEIGHT-2].index {|s| s[3..WIDTH-4].index(COL_EMPTY) == nil}) != nil
|
50
|
+
(ind-1).step(0,-1) {|i| @m[i+1] = @m[i]}
|
51
|
+
@m[0] = @m[HEIGHT+1].dup
|
52
|
+
end
|
53
|
+
(0..HEIGHT-1).each {|y| (2..WIDTH-3).each {|x| brick!(y,x,@m[y][x])}} # Update the screen (field + borders)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
# Initialize the console and program data
|
57
|
+
init_screen; clear; noecho; stdscr.keypad(true)
|
58
|
+
fig, scr, speed = Figure.new, GameField.new, 1
|
59
|
+
# Keyboard control thread
|
60
|
+
keythread = Thread.new { loop {
|
61
|
+
case getch
|
62
|
+
when Key::LEFT then fig.move!(->f{f.x -=1}, ->f{f.x +=1}, scr)
|
63
|
+
when Key::RIGHT then fig.move!(->f{f.x +=1}, ->f{f.x -=1}, scr)
|
64
|
+
when Key::UP then fig.move!(->f{f.rot = (f.rot+1)%4}, ->f{f.rot = (f.rot+3)%4},scr)
|
65
|
+
when Key::DOWN then speed = 0.05 # Delay for fast falling
|
66
|
+
end
|
67
|
+
}}
|
68
|
+
# Game main loop (new figure creation + falling)
|
69
|
+
begin
|
70
|
+
fig, speed = Figure.new, 0.5 # Figure and delay for its normal falling
|
71
|
+
sleep(speed) while fig.move!(->f{f.y +=1}, ->f{f.y -=1}, scr)
|
72
|
+
scr.lines!
|
73
|
+
end until fig.y == 0
|
74
|
+
# Finish the game
|
75
|
+
keythread.kill
|
76
|
+
setpos(GameField::HEIGHT/2,GameField::WIDTH-4)
|
77
|
+
addstr("GAME OVER!")
|
78
|
+
getch
|
79
|
+
close_screen
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: node-marshal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey Voskov
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir:
|
10
10
|
- bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2017-05-01 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: "This gem is designed for transformation of Ruby source code (eiher in
|
15
15
|
the form of files or strings) to the \nRuby nodes (syntax trees) used by Ruby MRI
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- test/test_base.rb
|
44
44
|
- test/test_complex.rb
|
45
45
|
- test/test_lifegame.rb
|
46
|
+
- test/test_namedarg.rb
|
46
47
|
- test/test_obfuscator.rb
|
47
48
|
- test/test_qcall.rb
|
48
49
|
- test/tinytet.rb
|
@@ -68,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
69
|
version: '0'
|
69
70
|
requirements: []
|
70
71
|
rubyforge_project:
|
71
|
-
rubygems_version: 2.5.
|
72
|
+
rubygems_version: 2.5.2
|
72
73
|
signing_key:
|
73
74
|
specification_version: 4
|
74
75
|
summary: Transforms Ruby sources to binary nodes (trees) that can be saved and loaded
|