tcl-ruby 0.1.0 → 0.1.1
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/.rubocop.yml +8 -0
- data/.travis.yml +1 -0
- data/README.md +7 -4
- data/lib/tcl/ruby.rb +5 -1
- data/lib/tcl/ruby/command.rb +78 -31
- data/lib/tcl/ruby/commands/array.rb +12 -23
- data/lib/tcl/ruby/commands/basic.rb +38 -37
- data/lib/tcl/ruby/commands/inout.rb +54 -0
- data/lib/tcl/ruby/commands/list.rb +90 -46
- data/lib/tcl/ruby/commands/string.rb +118 -0
- data/lib/tcl/ruby/error.rb +3 -3
- data/lib/tcl/ruby/list_array.rb +54 -23
- data/lib/tcl/ruby/option_parser.rb +28 -0
- data/lib/tcl/ruby/parser.rb +90 -58
- data/lib/tcl/ruby/string.rb +39 -0
- data/lib/tcl/ruby/util.rb +32 -1
- data/lib/tcl/ruby/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07b644f73103f389ffc7575edd8a550b330f6774
|
4
|
+
data.tar.gz: 55726309ea62a15b0d77e67c5f6462b44b561303
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89b1f5f58c6058715c363f13b10825c4e03592e67ea176abdcc5b4f51f7f6d46a5aa5984fe0b55684d80683eea2e9ded573b479a906b8b4d971fccabe839f3a0
|
7
|
+
data.tar.gz: ebc2b1bf14efde9a4f53b76ca863847b08bd1fefecd2d1ef22c804f65a85be6a1150b20caba4371357c3371b1e4e14daa47d582edca01623d80d8bdf8bdb29d0
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[](https://codeclimate.com/github/kiyonori-matsumoto/tcl-ruby) [](https://travis-ci.org/kiyonori-matsumoto/tcl-ruby)
|
1
|
+
[](https://codeclimate.com/github/kiyonori-matsumoto/tcl-ruby) [](https://travis-ci.org/kiyonori-matsumoto/tcl-ruby) [](https://badge.fury.io/rb/tcl-ruby)
|
2
2
|
|
3
3
|
# Tcl::Ruby
|
4
4
|
|
@@ -23,19 +23,22 @@ Or install it yourself as:
|
|
23
23
|
## Usage
|
24
24
|
|
25
25
|
Instanciate Interpreter
|
26
|
+
|
26
27
|
```ruby
|
27
|
-
f = Interpreter.new
|
28
|
+
f = Tcl::Ruby::Interpreter.new
|
28
29
|
```
|
29
30
|
Parse commands you want to
|
31
|
+
|
30
32
|
```ruby
|
31
33
|
f.parse('llength {A B C D}')
|
32
|
-
=> 4
|
34
|
+
# => 4
|
33
35
|
```
|
34
36
|
You can get variables with Interpreter#variables
|
37
|
+
|
35
38
|
```ruby
|
36
39
|
f.parse('set A 123')
|
37
40
|
f.variables('A')
|
38
|
-
=> '123'
|
41
|
+
# => '123'
|
39
42
|
```
|
40
43
|
|
41
44
|
## Development
|
data/lib/tcl/ruby.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
require 'tcl/ruby/command.rb'
|
2
2
|
require 'tcl/ruby/error.rb'
|
3
3
|
require 'tcl/ruby/list_array.rb'
|
4
|
+
require 'tcl/ruby/option_parser.rb'
|
4
5
|
require 'tcl/ruby/parser.rb'
|
6
|
+
require 'tcl/ruby/string.rb'
|
5
7
|
require 'tcl/ruby/util.rb'
|
8
|
+
require 'tcl/ruby/commands/array.rb'
|
6
9
|
require 'tcl/ruby/commands/basic.rb'
|
10
|
+
require 'tcl/ruby/commands/inout.rb'
|
7
11
|
require 'tcl/ruby/commands/list.rb'
|
8
|
-
require 'tcl/ruby/commands/
|
12
|
+
require 'tcl/ruby/commands/string.rb'
|
data/lib/tcl/ruby/command.rb
CHANGED
@@ -1,52 +1,96 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
1
3
|
module Tcl
|
2
4
|
module Ruby
|
3
5
|
class Interpreter
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
arg
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@hooks[
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
6
|
+
private
|
7
|
+
|
8
|
+
def command(cmds)
|
9
|
+
ret = nil
|
10
|
+
cmds.each do |arg|
|
11
|
+
next if arg.empty?
|
12
|
+
arg.replace(&method(:replace))
|
13
|
+
name = "___#{arg[0]}"
|
14
|
+
if @proc.key?(arg[0]) then ret = exec_proc(arg[1..-1], @proc[arg[0]])
|
15
|
+
elsif @hooks.key?(arg[0]) then ret = @hooks[arg[0]].call(arg[1..-1])
|
16
|
+
elsif respond_to?(name, true)
|
17
|
+
begin
|
18
|
+
ret = send(name, *arg[1..-1])
|
19
|
+
rescue ArgumentError => e
|
20
|
+
raise(TclArgumentError, "#{arg[0]}: #{e.message}")
|
21
|
+
end
|
22
|
+
else
|
23
|
+
raise(CommandError, "command not found, #{arg[0]}")
|
24
|
+
end
|
18
25
|
end
|
26
|
+
ret
|
19
27
|
end
|
20
28
|
|
21
29
|
def replace(list)
|
22
|
-
|
30
|
+
# replace commands
|
31
|
+
list = replace_commands(list)
|
32
|
+
|
23
33
|
# replace variable
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
34
|
+
replace_variable(list)
|
35
|
+
end
|
36
|
+
|
37
|
+
def replace_commands(list)
|
38
|
+
l = list.dup
|
39
|
+
s = StringScanner.new(l)
|
40
|
+
buffer = nil
|
41
|
+
depth = 0
|
42
|
+
until s.empty?
|
43
|
+
if s.scan(/\\./m)
|
44
|
+
buffer << s[0] if buffer
|
45
|
+
elsif s.scan(/\[/)
|
46
|
+
if depth == 0
|
47
|
+
pos = s.pos - 1
|
48
|
+
buffer = ''
|
49
|
+
end
|
50
|
+
depth += 1
|
51
|
+
buffer << s[0]
|
52
|
+
elsif s.scan(/\]/)
|
53
|
+
depth -= 1
|
54
|
+
buffer << s[0]
|
55
|
+
if depth == 0
|
56
|
+
l[pos, buffer.length] = parse(buffer[1..-2]).to_s
|
57
|
+
s.string = l
|
58
|
+
buffer = nil
|
59
|
+
end
|
60
|
+
elsif s.scan(/[^\[\]\\]+/m)
|
61
|
+
buffer << s[0] if buffer
|
31
62
|
end
|
32
|
-
|
63
|
+
end
|
64
|
+
raise(ParseError, 'unmatched brackets') if depth != 0
|
65
|
+
l
|
66
|
+
end
|
67
|
+
|
68
|
+
def replace_variable(elem)
|
69
|
+
elem.gsub!(/\$\{(.+?)\}|\$(\w+\([^\s)]+\))|\$(\w+)/) do |_|
|
70
|
+
v = Regexp.last_match(1) || Regexp.last_match(2) ||
|
71
|
+
Regexp.last_match(3)
|
72
|
+
h = nil
|
73
|
+
vv = v.dup
|
74
|
+
v.sub!(/\(([^\s)]+)\)\z/) { |_m| h = Regexp.last_match(1); '' }
|
75
|
+
raise TclVariableNotFoundError.new(v, 'no such variable') unless
|
33
76
|
@variables.key?(v)
|
34
|
-
if h
|
35
|
-
raise(
|
36
|
-
|
77
|
+
if h # variable specified is hash
|
78
|
+
raise TclVariableNotFoundError.new(vv, "variable isn't array") unless @variables[v].is_a?(Hash)
|
79
|
+
h = replace_variable(h) # analyze var_string on parenthesis
|
80
|
+
@variables[v][h]
|
37
81
|
else
|
38
|
-
raise(
|
82
|
+
raise TclVariableNotFoundError.new(v, 'variable is array') if
|
83
|
+
@variables[v].is_a?(Hash)
|
39
84
|
@variables[v]
|
40
85
|
end
|
41
86
|
end
|
42
|
-
|
43
|
-
l = l.gsub(/\[(.+)\]/) { parse(Regexp.last_match(1)) }
|
87
|
+
elem
|
44
88
|
end
|
45
89
|
|
46
90
|
def exec_proc(arg, proc_info)
|
47
91
|
proc_arg = parse(proc_info[0], true)
|
48
92
|
raise(TclArgumentError, proc_arg.to_s) if proc_arg.size != arg.size
|
49
|
-
@variables[:___global].each do |v| #
|
93
|
+
@variables[:___global].each do |v| # backup globals
|
50
94
|
@global[v] = @variables[v]
|
51
95
|
end if @variables.key?(:___global)
|
52
96
|
@v_stack.push(@variables)
|
@@ -57,10 +101,13 @@ module Tcl
|
|
57
101
|
ret = catch(:return) do
|
58
102
|
parse(proc_info[1])
|
59
103
|
end
|
60
|
-
@variables[:___global].each do |v| #
|
104
|
+
@variables[:___global].each do |v| # write back
|
61
105
|
@global[v] = @variables[v]
|
62
106
|
end if @variables.key?(:___global)
|
63
107
|
@variables = @v_stack.pop
|
108
|
+
@variables[:___global].each do |v| # re-copy global
|
109
|
+
@variables[v] = @global[v]
|
110
|
+
end if @variables.key?(:___global)
|
64
111
|
ret
|
65
112
|
end
|
66
113
|
end
|
@@ -3,28 +3,23 @@ module Tcl
|
|
3
3
|
class Interpreter
|
4
4
|
private
|
5
5
|
|
6
|
-
def ___array(arg)
|
7
|
-
send("___array_#{arg[0]}", arg[1..-1])
|
6
|
+
def ___array(*arg)
|
7
|
+
send("___array_#{arg[0]}", *arg[1..-1])
|
8
|
+
rescue ArgumentError => e
|
9
|
+
raise(TclArgumentError, "array #{arg[0]}: #{e.message}")
|
8
10
|
end
|
9
11
|
|
10
|
-
def ___array_set(
|
11
|
-
name = arg[0]
|
12
|
+
def ___array_set(name, list)
|
12
13
|
raise(CommandError, "#{name} is not array") unless
|
13
14
|
@variables[name].is_a?(Hash) || !@variables.key?(name)
|
14
|
-
l = parse(
|
15
|
-
raise(TclArgumentError, 'list must have an even number of elements') unless
|
16
|
-
l.size.even?
|
15
|
+
l = parse(list, true).to_h
|
17
16
|
@variables[name] ||= {}
|
18
|
-
@variables[name].merge!(
|
17
|
+
@variables[name].merge!(l)
|
19
18
|
end
|
20
19
|
|
21
|
-
def ___array_unset(
|
22
|
-
raise(TclArgumentError, 'array unset arrayName ?pattern?') unless
|
23
|
-
(1..2).cover?(arg.size)
|
24
|
-
name = arg[0]
|
20
|
+
def ___array_unset(name, pattern = nil)
|
25
21
|
return '' unless @variables[name].is_a?(Hash)
|
26
|
-
if
|
27
|
-
pattern = arg[1]
|
22
|
+
if pattern
|
28
23
|
@variables[name].delete(pattern)
|
29
24
|
else
|
30
25
|
@variables.delete(name)
|
@@ -32,13 +27,9 @@ module Tcl
|
|
32
27
|
''
|
33
28
|
end
|
34
29
|
|
35
|
-
def ___array_get(
|
36
|
-
raise(TclArgumentError, 'array get arrayName ?pattern?') unless
|
37
|
-
(1..2).cover?(arg.size)
|
38
|
-
name = arg[0]
|
30
|
+
def ___array_get(name, pattern = nil)
|
39
31
|
return '' unless @variables[name].is_a?(Hash)
|
40
|
-
if
|
41
|
-
pattern = arg[1]
|
32
|
+
if pattern
|
42
33
|
return '' unless @variables[name].key?(pattern)
|
43
34
|
"#{pattern} #{@variables[name][pattern]}"
|
44
35
|
else
|
@@ -46,9 +37,7 @@ module Tcl
|
|
46
37
|
end
|
47
38
|
end
|
48
39
|
|
49
|
-
def ___array_exists(
|
50
|
-
raise(TclArgumentError, 'array exists arrayName') unless arg.size == 1
|
51
|
-
name = arg[0]
|
40
|
+
def ___array_exists(name)
|
52
41
|
@variables[name].is_a?(Hash) ? '1' : '0'
|
53
42
|
end
|
54
43
|
end
|
@@ -3,18 +3,27 @@ module Tcl
|
|
3
3
|
class Interpreter
|
4
4
|
private
|
5
5
|
|
6
|
-
def ___set(
|
7
|
-
|
8
|
-
(1
|
9
|
-
|
10
|
-
|
6
|
+
def ___set(var_name, value = nil)
|
7
|
+
if (m = var_name.match(/(\w+)\((\S+?)\)/))
|
8
|
+
___array_set(m[1], "{#{m[2]}} {#{value}}") if value
|
9
|
+
___array_get(m[1], "{#{m[2]}}")
|
10
|
+
else
|
11
|
+
@variables[var_name] = value if value
|
12
|
+
@variables[var_name]
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
|
-
def ___expr(arg)
|
16
|
+
def ___expr(*arg)
|
14
17
|
eval arg.join('')
|
15
18
|
end
|
16
19
|
|
17
|
-
def
|
20
|
+
def ___eval(*arg)
|
21
|
+
raise(TclArgumentError, 'wrong number of arguments(0 for 1..)') if
|
22
|
+
arg.empty?
|
23
|
+
parse(___concat(*arg))
|
24
|
+
end
|
25
|
+
|
26
|
+
def ___if(*arg)
|
18
27
|
arg.delete('then')
|
19
28
|
arg.delete('else')
|
20
29
|
arg.delete('elseif')
|
@@ -27,20 +36,19 @@ module Tcl
|
|
27
36
|
nil
|
28
37
|
end
|
29
38
|
|
30
|
-
def ___for(
|
31
|
-
|
32
|
-
parse(arg[0])
|
39
|
+
def ___for(start, tst, nxt, body)
|
40
|
+
parse(start)
|
33
41
|
catch(:break) do
|
34
|
-
while eval(replace(
|
42
|
+
while eval(replace(tst))
|
35
43
|
catch(:continue) do
|
36
|
-
parse(
|
44
|
+
parse(body)
|
37
45
|
end
|
38
|
-
parse(
|
46
|
+
parse(nxt)
|
39
47
|
end
|
40
48
|
end
|
41
49
|
end
|
42
50
|
|
43
|
-
def ___foreach(arg)
|
51
|
+
def ___foreach(*arg)
|
44
52
|
varlist = []
|
45
53
|
list = []
|
46
54
|
while arg[2]
|
@@ -48,26 +56,22 @@ module Tcl
|
|
48
56
|
list << parse(arg[1], true)
|
49
57
|
arg.shift(2)
|
50
58
|
end
|
51
|
-
body = arg[0]
|
52
59
|
catch(:break) do
|
53
60
|
while list.any?(&:any?)
|
54
61
|
# assign variables
|
55
62
|
varlist.each_with_index do |v, idx|
|
56
|
-
v.each
|
57
|
-
@variables[vv] = list[idx].shift || ''
|
58
|
-
end
|
63
|
+
v.each { |vv| @variables[vv] = list[idx].shift || '' }
|
59
64
|
end
|
60
65
|
catch(:continue) do
|
61
|
-
parse(
|
66
|
+
parse(arg[0])
|
62
67
|
end
|
63
68
|
end
|
64
69
|
end
|
65
70
|
end
|
66
71
|
|
67
|
-
def ___while(
|
68
|
-
body = arg[1]
|
72
|
+
def ___while(tst, body)
|
69
73
|
catch(:break) do
|
70
|
-
while eval(replace(
|
74
|
+
while eval(replace(tst))
|
71
75
|
catch(:continue) do
|
72
76
|
parse(body)
|
73
77
|
end
|
@@ -75,41 +79,38 @@ module Tcl
|
|
75
79
|
end
|
76
80
|
end
|
77
81
|
|
78
|
-
def ___break
|
82
|
+
def ___break
|
79
83
|
throw :break
|
80
84
|
end
|
81
85
|
|
82
|
-
def ___continue
|
86
|
+
def ___continue
|
83
87
|
throw :continue
|
84
88
|
end
|
85
89
|
|
86
|
-
def ___return(
|
87
|
-
throw(:return,
|
90
|
+
def ___return(val = nil)
|
91
|
+
throw(:return, val)
|
88
92
|
end
|
89
93
|
|
90
|
-
def ___incr(
|
91
|
-
|
92
|
-
|
93
|
-
@variables[arg[0]] = ((@variables[arg[0]] || 0).to_i + incr).to_s
|
94
|
+
def ___incr(var_name, increment = 1)
|
95
|
+
@variables[var_name] = ((@variables[var_name] || 0).to_i +
|
96
|
+
increment.to_i).to_s
|
94
97
|
end
|
95
98
|
|
96
|
-
def
|
97
|
-
|
99
|
+
def ___format(str, *args)
|
100
|
+
str % args
|
98
101
|
end
|
99
102
|
|
100
|
-
def ___proc(
|
101
|
-
|
102
|
-
@proc[arg[0]] = arg[1..2]
|
103
|
+
def ___proc(name, args, body)
|
104
|
+
@proc[name] = [args, body]
|
103
105
|
end
|
104
106
|
|
105
|
-
def ___global(arg)
|
107
|
+
def ___global(*arg)
|
106
108
|
@variables[:___global] ||= []
|
107
109
|
arg.each do |v|
|
108
110
|
@variables[:___global] << v
|
109
111
|
@variables[v] = @global[v] if @global
|
110
112
|
end
|
111
113
|
end
|
112
|
-
# define_method('___#') { |_p| nil }
|
113
114
|
end
|
114
115
|
end
|
115
116
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Tcl
|
2
|
+
module Ruby
|
3
|
+
class Interpreter
|
4
|
+
private
|
5
|
+
|
6
|
+
def ___open(filename, access = 'r', permission = 0744)
|
7
|
+
begin
|
8
|
+
fp = open(filename, access, permission)
|
9
|
+
rescue
|
10
|
+
raise(CommandError, "File #{filename} cannot open")
|
11
|
+
end
|
12
|
+
k = "file#{fp.object_id.to_s(36)}"
|
13
|
+
@files[k] = fp
|
14
|
+
k
|
15
|
+
end
|
16
|
+
|
17
|
+
def ___close(id)
|
18
|
+
fp = get_fp(id, delete: true)
|
19
|
+
fp.close
|
20
|
+
end
|
21
|
+
|
22
|
+
def ___gets(id, var_name = nil)
|
23
|
+
fp = get_fp(id)
|
24
|
+
str = fp.gets
|
25
|
+
if var_name
|
26
|
+
@variables[var_name] = str
|
27
|
+
str.length
|
28
|
+
else
|
29
|
+
str
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def ___puts(*arg)
|
34
|
+
opts = {}
|
35
|
+
opts = OptionParser.parse(['nonewline'], arg) if arg.size != 1
|
36
|
+
__puts_body(*arg, opts)
|
37
|
+
end
|
38
|
+
|
39
|
+
def __puts_body(id = nil, val, nonewline: false)
|
40
|
+
fp = id ? get_fp(id) : $stdout
|
41
|
+
if nonewline
|
42
|
+
fp.print val
|
43
|
+
else
|
44
|
+
fp.puts val
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def ___eof(id)
|
49
|
+
fp = get_fp(id)
|
50
|
+
fp.eof? ? '1' : '0'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -3,69 +3,113 @@ module Tcl
|
|
3
3
|
class Interpreter
|
4
4
|
private
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
parse(arg[0], true).size
|
6
|
+
def ___concat(*arg)
|
7
|
+
arg.map(&:strip).join(' ')
|
9
8
|
end
|
10
9
|
|
11
|
-
def
|
12
|
-
|
10
|
+
def ___llength(list)
|
11
|
+
parse(list, true).size.to_s
|
13
12
|
end
|
14
13
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
if (0...l.size).cover?(pos)
|
28
|
-
l = l[pos]
|
29
|
-
else
|
30
|
-
return ''
|
31
|
-
end
|
32
|
-
end
|
14
|
+
def ___list(*arg)
|
15
|
+
ListArray.new(arg).to_list
|
16
|
+
end
|
17
|
+
|
18
|
+
def ___lindex(list, *indexes)
|
19
|
+
return list if indexes.nil? || indexes.empty?
|
20
|
+
l = list
|
21
|
+
indexes.each do |as|
|
22
|
+
parse(as, true).each do |a|
|
23
|
+
l = parse(l, true)
|
24
|
+
pos = parse_index_format(a)
|
25
|
+
l = l[pos]
|
33
26
|
end
|
34
|
-
l
|
35
27
|
end
|
28
|
+
l || ''
|
36
29
|
end
|
37
30
|
|
38
|
-
def ___join(
|
39
|
-
|
40
|
-
separator = arg[1] || ' '
|
41
|
-
parse(arg[0], true).join(separator)
|
31
|
+
def ___join(list, separator = ' ')
|
32
|
+
parse(list, true).join(separator)
|
42
33
|
end
|
43
34
|
|
44
|
-
def ___linsert(
|
45
|
-
|
46
|
-
l
|
47
|
-
l.insert(arg[1].to_i, *arg[2..-1])
|
48
|
-
# "{#{l.join(' ')}}"
|
35
|
+
def ___linsert(list, index, element, *elements)
|
36
|
+
l = parse(list, true)
|
37
|
+
l.insert(parse_index_format(index), element, *elements)
|
49
38
|
l.to_list
|
50
39
|
end
|
51
40
|
|
52
|
-
def ___lrange(
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
last
|
57
|
-
|
58
|
-
|
59
|
-
|
41
|
+
def ___lrange(list, first, last)
|
42
|
+
first = parse_index_format first
|
43
|
+
last = parse_index_format last
|
44
|
+
l = parse(list, true)
|
45
|
+
l[first..last].to_list
|
46
|
+
end
|
47
|
+
|
48
|
+
def ___lappend(var_name, *values)
|
49
|
+
l = parse(variables(var_name), true)
|
50
|
+
l.push(*values)
|
51
|
+
@variables[var_name] = l.to_list
|
52
|
+
end
|
53
|
+
|
54
|
+
def ___lsort(*args)
|
55
|
+
opts = {}
|
56
|
+
if args.size > 1
|
57
|
+
opts = OptionParser.parse(
|
58
|
+
['ascii', 'dictionary', 'integer', 'real', 'command?', 'increasing',
|
59
|
+
'decreasing', 'index?', 'unique'], args)
|
60
|
+
end
|
61
|
+
__lsort_body(*args, opts)
|
62
|
+
end
|
63
|
+
|
64
|
+
def __lsort_body(list, opts)
|
65
|
+
l = parse(list, true)
|
66
|
+
func = if opts['directionary'] then :upcase
|
67
|
+
elsif opts['integer'] then :to_i
|
68
|
+
elsif opts['real'] then :to_f
|
69
|
+
else :to_s
|
70
|
+
end
|
71
|
+
if opts['index']
|
72
|
+
index = parse_index_format(opts['index'])
|
73
|
+
sort_func = -> (x) { parse(x, true)[index].send(func) }
|
60
74
|
else
|
61
|
-
|
75
|
+
sort_func = func
|
62
76
|
end
|
77
|
+
l.uniq!(&sort_func) if opts['unique']
|
78
|
+
l.sort_by!(&sort_func)
|
79
|
+
l.reverse! if opts['decreasing']
|
80
|
+
ListArray.new(l).to_list
|
63
81
|
end
|
64
82
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
|
83
|
+
def ___lsearch(*args)
|
84
|
+
opts = {}
|
85
|
+
if args.size > 2
|
86
|
+
opts = OptionParser.parse(
|
87
|
+
['all', 'ascii', 'decreasing', 'dictionary', 'exact', 'glob',
|
88
|
+
'increasing', 'inline', 'integer', 'not', 'real', 'regexp',
|
89
|
+
'sorted', 'start?'], args)
|
90
|
+
end
|
91
|
+
__lsearch_body(*args, opts)
|
92
|
+
end
|
93
|
+
|
94
|
+
def __lsearch_body(list, pattern, opts)
|
95
|
+
l = parse(list, true)
|
96
|
+
func = case [opts['all'], opts['inline']]
|
97
|
+
when [true, true] then :select
|
98
|
+
when [true, nil] then :find_index_all
|
99
|
+
when [nil, true] then :find
|
100
|
+
else :index
|
101
|
+
end
|
102
|
+
block = if opts['regexp'] then -> (b, x) { !!(x =~ /#{pattern}/) == b }
|
103
|
+
elsif opts['exact'] then -> (b, x) { (x == pattern) == b }
|
104
|
+
else
|
105
|
+
pattern.gsub!(/\*/, '.*')
|
106
|
+
pattern.tr!('?', '.')
|
107
|
+
pattern.gsub!(/\\(.)/) { Regexp.last_match(1) }
|
108
|
+
-> (b, x) { !!(x =~ /\A#{pattern}\z/) == b }
|
109
|
+
end.curry
|
110
|
+
|
111
|
+
v = l.send(func, &block.call(!opts['not']))
|
112
|
+
ListArray.new(v).to_list
|
69
113
|
end
|
70
114
|
end
|
71
115
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
module Tcl
|
4
|
+
module Ruby
|
5
|
+
class Interpreter
|
6
|
+
private
|
7
|
+
|
8
|
+
def ___string(*arg)
|
9
|
+
send("___string_#{arg[0]}", *arg[1..-1])
|
10
|
+
rescue ArgumentError => e
|
11
|
+
raise(TclArgumentError, "string #{arg[0]}: #{e.message}")
|
12
|
+
end
|
13
|
+
|
14
|
+
def ___string_length(str)
|
15
|
+
str.length
|
16
|
+
end
|
17
|
+
|
18
|
+
def ___string_equal(*arg)
|
19
|
+
opts = {}
|
20
|
+
if arg.size != 2
|
21
|
+
opts = OptionParser.parse(['nocase', 'length?'], arg)
|
22
|
+
raise(TclArgumentError, 'string equal ?-nocase? ?-length int? string1 string2') unless arg.size == 2
|
23
|
+
end
|
24
|
+
__string_equal_body(*arg, opts)
|
25
|
+
end
|
26
|
+
|
27
|
+
def __string_equal_body(str1, str2, opts = {})
|
28
|
+
if opts.key?('nocase')
|
29
|
+
str1 = str1.upcase
|
30
|
+
str2 = str2.upcase
|
31
|
+
end
|
32
|
+
if opts.key?('length')
|
33
|
+
range = (0...opts['length'].to_i)
|
34
|
+
(str1[range] == str2[range]) ? '1' : '0'
|
35
|
+
else
|
36
|
+
(str1 == str2) ? '1' : '0'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def ___string_index(str, index)
|
41
|
+
str[parse_index_format(index)]
|
42
|
+
end
|
43
|
+
|
44
|
+
def ___string_map(*arg)
|
45
|
+
opts = {}
|
46
|
+
if arg.size != 2
|
47
|
+
opts = OptionParser.parse(['nocase'], arg)
|
48
|
+
raise(TclArgumentError, 'string map ?-nocase? charMap string') unless arg.size == 2
|
49
|
+
end
|
50
|
+
__string_map_body(*arg, opts)
|
51
|
+
end
|
52
|
+
|
53
|
+
def __string_map_body(char_map, str, opts = {})
|
54
|
+
h = parse(char_map, true).to_h
|
55
|
+
scan = StringScanner.new str
|
56
|
+
rstr = ''
|
57
|
+
until scan.empty?
|
58
|
+
r = h.each do |k, v|
|
59
|
+
next unless (opts['nocase'] && scan.scan(/#{k}/i)) ||
|
60
|
+
scan.scan(/#{k}/)
|
61
|
+
rstr << v
|
62
|
+
break false
|
63
|
+
end
|
64
|
+
rstr << scan.scan(/./) if r
|
65
|
+
end
|
66
|
+
rstr
|
67
|
+
end
|
68
|
+
|
69
|
+
def ___string_range(str, first, last)
|
70
|
+
first = parse_index_format first
|
71
|
+
last = parse_index_format last
|
72
|
+
str[first..last]
|
73
|
+
end
|
74
|
+
|
75
|
+
def ___string_repeat(str, count)
|
76
|
+
str * count.to_i
|
77
|
+
end
|
78
|
+
|
79
|
+
def ___string_tolower(str, first = 0, last = nil)
|
80
|
+
last ||= str.size
|
81
|
+
__string_tosomething(str, first, last, :downcase)
|
82
|
+
end
|
83
|
+
|
84
|
+
def __string_tosomething(str, first, last, modifier)
|
85
|
+
first = parse_index_format first
|
86
|
+
last = parse_index_format last
|
87
|
+
str[first..last] = str[first..last].send(modifier)
|
88
|
+
str
|
89
|
+
end
|
90
|
+
|
91
|
+
def ___string_totitle(str, first = 0, last = -1)
|
92
|
+
__string_tosomething(str, first, last, :capitalize)
|
93
|
+
end
|
94
|
+
|
95
|
+
def ___string_toupper(str, first = 0, last = -1)
|
96
|
+
__string_tosomething(str, first, last, :upcase)
|
97
|
+
end
|
98
|
+
|
99
|
+
def ___string_trim(str, chars = '\s')
|
100
|
+
__string_trimmer(str, chars, 3)
|
101
|
+
end
|
102
|
+
|
103
|
+
def ___string_trimleft(str, chars = '\s')
|
104
|
+
__string_trimmer(str, chars, 1)
|
105
|
+
end
|
106
|
+
|
107
|
+
def ___string_trimright(str, chars = '\s')
|
108
|
+
__string_trimmer(str, chars, 2)
|
109
|
+
end
|
110
|
+
|
111
|
+
def __string_trimmer(str, chars, mode)
|
112
|
+
str.sub!(/\A[#{chars}]+/, '') if mode & 1 != 0
|
113
|
+
str.sub!(/[#{chars}]+\z/, '') if mode & 2 != 0
|
114
|
+
str
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/tcl/ruby/error.rb
CHANGED
@@ -4,9 +4,9 @@ module Tcl
|
|
4
4
|
class ParseError < TclError; end
|
5
5
|
class CommandError < TclError; end
|
6
6
|
class TclArgumentError < TclError
|
7
|
-
def initialize(msg)
|
8
|
-
|
9
|
-
end
|
7
|
+
# def initialize(msg)
|
8
|
+
# super("wrong \# args: should be\"#{msg}\"")
|
9
|
+
# end
|
10
10
|
end
|
11
11
|
class TclVariableNotFoundError < TclError
|
12
12
|
def initialize(var, type = '')
|
data/lib/tcl/ruby/list_array.rb
CHANGED
@@ -1,33 +1,77 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
module Tcl
|
2
4
|
module Ruby
|
3
5
|
class ListArray
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegators :@ary, :find, :any?
|
9
|
+
|
4
10
|
Array.public_instance_methods(false).each do |name|
|
5
|
-
next if name == '<<'
|
6
11
|
define_method(name) do |*args, &block|
|
7
12
|
@ary.send(name, *args, &block)
|
8
13
|
end
|
9
14
|
end
|
10
15
|
|
11
|
-
def
|
16
|
+
def uniq!(&block)
|
17
|
+
@ary = @ary.reverse.uniq(&block).reverse
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def uniq(&block)
|
22
|
+
dup.uniq!(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_index_all
|
26
|
+
raise ArgumentError unless block_given?
|
27
|
+
r = []
|
28
|
+
@ary.each_with_index do |e, idx|
|
29
|
+
r << idx.to_s if yield(e)
|
30
|
+
end
|
31
|
+
r
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(ary = [])
|
35
|
+
@ary = Array(ary).map(&:to_s)
|
36
|
+
@brackets = []
|
37
|
+
end
|
38
|
+
|
39
|
+
def clear
|
12
40
|
@ary = []
|
41
|
+
@brackets = []
|
42
|
+
end
|
43
|
+
|
44
|
+
def bracket_add(val)
|
45
|
+
@brackets[@ary.size] ||= []
|
46
|
+
@brackets[@ary.size] << val
|
13
47
|
end
|
14
48
|
|
15
49
|
def <<(buffer)
|
16
50
|
@ary << buffer.dup unless buffer.empty?
|
17
51
|
buffer.clear
|
52
|
+
buffer.init
|
18
53
|
self
|
19
54
|
end
|
20
55
|
|
21
56
|
def to_string
|
22
|
-
@ary.map!
|
57
|
+
@ary.map!(&:to_tcl_string)
|
23
58
|
self
|
24
59
|
end
|
25
60
|
|
26
61
|
def to_list
|
27
|
-
@ary.map
|
62
|
+
@ary.map(&:to_tcl_list).join(' ')
|
63
|
+
end
|
64
|
+
|
65
|
+
def replace
|
66
|
+
@ary.size.times do |n|
|
67
|
+
@ary[n] = yield(@ary[n]) unless @ary[n].brace?
|
68
|
+
end
|
69
|
+
# @ary.map! { |m| m.brace? ? m : yield(m) }
|
70
|
+
self
|
28
71
|
end
|
29
72
|
|
30
73
|
def map!(&block)
|
74
|
+
@ary.each(&:init)
|
31
75
|
@ary.map!(&block)
|
32
76
|
self
|
33
77
|
end
|
@@ -48,28 +92,15 @@ module Tcl
|
|
48
92
|
end
|
49
93
|
end
|
50
94
|
|
95
|
+
def to_h
|
96
|
+
raise(TclArgumentError, 'list must have an even number of elements') if
|
97
|
+
@ary.size.odd?
|
98
|
+
Hash[@ary.each_slice(2).to_a]
|
99
|
+
end
|
100
|
+
|
51
101
|
protected
|
52
102
|
|
53
103
|
attr_accessor :ary
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def _to_string(str)
|
58
|
-
if str[0] == '{' && str[-1] == '}'
|
59
|
-
str = str[1..-2]
|
60
|
-
elsif str[0] == '"' && str[-1] == '"'
|
61
|
-
str = str[1..-2]
|
62
|
-
end
|
63
|
-
str
|
64
|
-
end
|
65
|
-
|
66
|
-
def _to_list(str)
|
67
|
-
if str == '' || str.match(/\s/)
|
68
|
-
"{#{str}}"
|
69
|
-
else
|
70
|
-
str
|
71
|
-
end
|
72
|
-
end
|
73
104
|
end
|
74
105
|
end
|
75
106
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Tcl
|
2
|
+
module Ruby
|
3
|
+
class OptionParser
|
4
|
+
# options_format
|
5
|
+
# array of string
|
6
|
+
# xxxx or xxxx?
|
7
|
+
# ? indicates that value has one argument
|
8
|
+
def self.parse(options, args)
|
9
|
+
ops = options.map do |e|
|
10
|
+
v = e.sub(/\?/, '')
|
11
|
+
["-#{v}", v, e[-1] == '?']
|
12
|
+
end
|
13
|
+
ret = {}
|
14
|
+
loop do
|
15
|
+
r = ops.each do |o|
|
16
|
+
next unless args[0] == o[0]
|
17
|
+
args.shift
|
18
|
+
ret[o[1]] = true
|
19
|
+
ret[o[1]] = args.shift if o[2]
|
20
|
+
break false
|
21
|
+
end
|
22
|
+
break if r
|
23
|
+
end
|
24
|
+
ret
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/tcl/ruby/parser.rb
CHANGED
@@ -3,68 +3,100 @@ require 'strscan'
|
|
3
3
|
module Tcl
|
4
4
|
module Ruby
|
5
5
|
class Interpreter
|
6
|
+
EX_CHAR_CHECK = lambda do |s, t|
|
7
|
+
(t && !s.check(/\s|\z/)) || (!t && !s.check(/\s|\z|;/))
|
8
|
+
end.curry
|
9
|
+
|
6
10
|
def parse(str, to_list = false)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
elsif
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
buffer
|
22
|
-
end
|
23
|
-
elsif s.scan(/\s+/)
|
24
|
-
if pdepth == 0 && ddepth == 0 && bdepth == 0
|
25
|
-
r << buffer
|
26
|
-
else
|
27
|
-
buffer << s[0]
|
28
|
-
end
|
29
|
-
else
|
30
|
-
buffer <<
|
31
|
-
if s.scan(/{/)
|
32
|
-
# pdepth += 1 if ddepth == 0
|
33
|
-
pdepth += 1 if buffer == '' || pdepth != 0
|
34
|
-
s[0]
|
35
|
-
elsif s.scan(/}/)
|
36
|
-
ret = s[0] # pdepth -= 1 if ddepth == 0
|
37
|
-
pdepth -= 1 if pdepth != 0
|
38
|
-
raise(ParseError, 'extra characters after close-brace') if
|
39
|
-
buffer[0] == '{' && pdepth == 0 && !s.check(/\s|\z/)
|
40
|
-
ret
|
41
|
-
elsif !to_list && s.scan(/\[/)
|
42
|
-
bdepth += 1 if pdepth == 0
|
43
|
-
s[0]
|
44
|
-
elsif !to_list && s.scan(/\]/)
|
45
|
-
bdepth -= 1 if pdepth == 0
|
46
|
-
s[0]
|
47
|
-
elsif s.scan(/"/)
|
48
|
-
ret = s[0]
|
49
|
-
ddepth = 1 - ddepth if buffer == '' || buffer[0] == '"'
|
50
|
-
raise(ParseError, 'extra characters after close-quote') if
|
51
|
-
buffer[0] == '"' && ddepth == 0 && !s.check(/\s|\z/)
|
52
|
-
ret
|
53
|
-
elsif s.scan(/\S/)
|
54
|
-
s[0]
|
55
|
-
else
|
56
|
-
raise(ParseError, "parse error #{s.rest}")
|
57
|
-
end
|
11
|
+
str2 = (str + "\n").gsub(/\\\n\s*/, ' ') # replace \ & \n & extra ws
|
12
|
+
@s = StringScanner.new(str2)
|
13
|
+
@list_array = ListArray.new
|
14
|
+
@pstack = [] # stack for brace, bracket, quote
|
15
|
+
@buffer = '' # ListElement.new('')'' # buffer for list element
|
16
|
+
@commands = []
|
17
|
+
until @s.empty?
|
18
|
+
if @s.scan(/\\./) then @buffer << @s[0]
|
19
|
+
elsif @s.scan(/\#/) then parse_comments
|
20
|
+
elsif !to_list && @s.scan(/\r\n|\r|\n|;/) then parse_command_ends
|
21
|
+
elsif @s.scan(/\s/) then parse_blanks
|
22
|
+
elsif @s.scan(/\S/)
|
23
|
+
@buffer << @s[0]
|
24
|
+
analyze_parentheses(to_list, EX_CHAR_CHECK[@s]) if
|
25
|
+
@buffer.parenthesis?
|
58
26
|
end
|
59
27
|
end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
28
|
+
check_pstack
|
29
|
+
to_list ? @list_array.to_string : command(@commands)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def check_pstack
|
35
|
+
raise(ParseError, "unmatched #{@pstack.last}s") if @pstack.any?
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_command_ends
|
39
|
+
bl = @s[0]
|
40
|
+
if @pstack.empty?
|
41
|
+
@list_array << @buffer
|
42
|
+
@list_array.to_string
|
43
|
+
@commands << @list_array.dup
|
44
|
+
@list_array.clear
|
65
45
|
else
|
66
|
-
|
67
|
-
|
46
|
+
@buffer << bl
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_blanks
|
51
|
+
@pstack.empty? ? @list_array << @buffer : @buffer << @s[0]
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_comments
|
55
|
+
if @buffer.empty? && @list_array.empty?
|
56
|
+
@s.scan(/.+$/)
|
57
|
+
else
|
58
|
+
@buffer << @s[0]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def matched_parentheses(id, has_ex_char)
|
63
|
+
if @pstack.last == id
|
64
|
+
r = @pstack.pop
|
65
|
+
if @pstack.empty? && has_ex_char
|
66
|
+
raise(ParseError, "extra characters after close-#{id}")
|
67
|
+
end
|
68
|
+
r
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def analyze_braces(to_list, extra_characters_check)
|
73
|
+
if @buffer[-1] == '{'
|
74
|
+
@pstack.push(:brace) if @pstack.last != :quote
|
75
|
+
else
|
76
|
+
matched_parentheses(:brace, extra_characters_check[to_list])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def analyze_quotes(to_list, extra_characters_check)
|
81
|
+
unless matched_parentheses(:quote, extra_characters_check[to_list])
|
82
|
+
@pstack.push :quote if @pstack.last != :brace
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def analyze_brackets
|
87
|
+
if @buffer[-1] == '[' && @pstack.last != :brace
|
88
|
+
@pstack.push :bracket
|
89
|
+
elsif @pstack.last == :bracket
|
90
|
+
@pstack.pop
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def analyze_parentheses(to_list, extra_characters_check)
|
95
|
+
bl = @buffer[-1]
|
96
|
+
case bl
|
97
|
+
when '{', '}' then analyze_braces(to_list, extra_characters_check)
|
98
|
+
when '[', ']' then analyze_brackets unless to_list
|
99
|
+
when '"' then analyze_quotes(to_list, extra_characters_check)
|
68
100
|
end
|
69
101
|
end
|
70
102
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class String
|
2
|
+
def brace?
|
3
|
+
@brace ||= self[0] == '{'
|
4
|
+
end
|
5
|
+
|
6
|
+
def bracket?
|
7
|
+
@bracket ||= self[0] == '['
|
8
|
+
end
|
9
|
+
|
10
|
+
def quote?
|
11
|
+
@quote ||= self[0] == '"'
|
12
|
+
end
|
13
|
+
|
14
|
+
def parenthesis?
|
15
|
+
brace? || bracket? || quote?
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_tcl_string
|
19
|
+
if parenthesis?
|
20
|
+
if (brace? && self[-1] == '}') || (quote? && self[-1] == '"')
|
21
|
+
b = self[1..-2]
|
22
|
+
clear << b
|
23
|
+
end
|
24
|
+
end
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_tcl_list
|
29
|
+
if self == '' || match(/\s/)
|
30
|
+
"{#{self}}"
|
31
|
+
else
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def init
|
37
|
+
@brace = @bracket = @quote = nil
|
38
|
+
end
|
39
|
+
end
|
data/lib/tcl/ruby/util.rb
CHANGED
@@ -7,10 +7,12 @@ module Tcl
|
|
7
7
|
@v_stack = []
|
8
8
|
@hooks = {}
|
9
9
|
@proc = {}
|
10
|
+
@files = {}
|
10
11
|
end
|
11
12
|
|
12
13
|
def variables(arg)
|
13
|
-
raise(
|
14
|
+
raise TclVariableNotFoundError.new(arg, 'no such variables') unless
|
15
|
+
@variables.key?(arg)
|
14
16
|
@variables[arg]
|
15
17
|
end
|
16
18
|
|
@@ -22,6 +24,35 @@ module Tcl
|
|
22
24
|
def delete_hook(name)
|
23
25
|
@hooks.delete(name.to_s)
|
24
26
|
end
|
27
|
+
|
28
|
+
def commands
|
29
|
+
r = []
|
30
|
+
r.concat private_methods.select { |e| e.match(/^___/) }
|
31
|
+
.map { |e| e[3..-1] }
|
32
|
+
r.concat @proc.keys
|
33
|
+
r.concat @hooks.keys
|
34
|
+
r
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def parse_index_format(a)
|
40
|
+
case a
|
41
|
+
when /end-(\d+)/ then -1 - Regexp.last_match(1).to_i
|
42
|
+
when /end/ then -1
|
43
|
+
else
|
44
|
+
r = a.to_i
|
45
|
+
r < 0 ? 0 : r
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_fp(id, delete: false)
|
50
|
+
if @files.key?(id)
|
51
|
+
delete ? @files.delete(id) : @files[id]
|
52
|
+
else
|
53
|
+
raise(CommandError, "cannnot find channel named #{id}")
|
54
|
+
end
|
55
|
+
end
|
25
56
|
end
|
26
57
|
end
|
27
58
|
end
|
data/lib/tcl/ruby/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tcl-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kiyonori Matsumoto
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -87,10 +87,14 @@ files:
|
|
87
87
|
- lib/tcl/ruby/command.rb
|
88
88
|
- lib/tcl/ruby/commands/array.rb
|
89
89
|
- lib/tcl/ruby/commands/basic.rb
|
90
|
+
- lib/tcl/ruby/commands/inout.rb
|
90
91
|
- lib/tcl/ruby/commands/list.rb
|
92
|
+
- lib/tcl/ruby/commands/string.rb
|
91
93
|
- lib/tcl/ruby/error.rb
|
92
94
|
- lib/tcl/ruby/list_array.rb
|
95
|
+
- lib/tcl/ruby/option_parser.rb
|
93
96
|
- lib/tcl/ruby/parser.rb
|
97
|
+
- lib/tcl/ruby/string.rb
|
94
98
|
- lib/tcl/ruby/util.rb
|
95
99
|
- lib/tcl/ruby/version.rb
|
96
100
|
- tcl-ruby.gemspec
|