tcl 0.0.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.
- data/.gitignore +1 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +58 -0
- data/TODO +2 -0
- data/VERSION +1 -0
- data/ext/tcl_ruby/extconf.rb +8 -0
- data/ext/tcl_ruby/tcl_ruby.c +225 -0
- data/lib/.gitignore +2 -0
- data/lib/tcl.rb +5 -0
- data/lib/tcl/interp.rb +51 -0
- data/lib/tcl/interp_helper.rb +25 -0
- data/lib/tcl/proc.rb +50 -0
- data/lib/tcl/var.rb +54 -0
- data/script/console +46 -0
- data/tcl.gemspec +70 -0
- data/test/fixtures/test.tcl +6 -0
- data/test/helper.rb +9 -0
- data/test/interp_receive_test.rb +106 -0
- data/test/interp_test.rb +107 -0
- data/test/proc_test.rb +42 -0
- data/test/test_helper.rb +15 -0
- data/test/var_test.rb +56 -0
- metadata +84 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Sam Stephenson
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
= tcl
|
2
|
+
|
3
|
+
A minimal Ruby interface to libtcl.
|
4
|
+
The library is written by Sam Stephenson. Aslak Hellesøy forked it to gemify it.
|
5
|
+
|
6
|
+
== Note on Patches/Pull Requests
|
7
|
+
|
8
|
+
* Fork the project.
|
9
|
+
* Make your feature addition or bug fix.
|
10
|
+
* Add tests for it. This is important so I don't break it in a
|
11
|
+
future version unintentionally.
|
12
|
+
* Commit, do not mess with rakefile, version, or history.
|
13
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
14
|
+
* Send me a pull request. Bonus points for topic branches.
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2009 Sam Stephenson. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "tcl"
|
8
|
+
gem.summary = %Q{Tcl bindings for Ruby}
|
9
|
+
gem.description = %Q{A minimal Ruby interface to libtcl}
|
10
|
+
gem.email = "sstephenson@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/sstephenson/ruby-tcl"
|
12
|
+
gem.authors = ["Sam Stephenson"]
|
13
|
+
|
14
|
+
gem.extensions = FileList['ext/tcl_ruby/extconf.rb']
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/*.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :test => [:check_dependencies, :compile]
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "tcl #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
55
|
+
|
56
|
+
require 'rake/extensiontask'
|
57
|
+
Rake::ExtensionTask.new("tcl_ruby")
|
58
|
+
CLEAN.include ['**/*.{o,bundle,jar,so,obj,pdb,lib,def,exp,log}']
|
data/TODO
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,225 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <tcl.h>
|
3
|
+
|
4
|
+
typedef struct {
|
5
|
+
Tcl_Interp *interp;
|
6
|
+
VALUE exit_exception;
|
7
|
+
} tcl_interp_struct;
|
8
|
+
|
9
|
+
static VALUE rb_value_to_s(VALUE value) {
|
10
|
+
return rb_funcall(value, rb_intern("to_s"), 0, 0);
|
11
|
+
}
|
12
|
+
|
13
|
+
static void rb_tcl_interp_destroy(tcl_interp_struct *tcl_interp) {
|
14
|
+
Tcl_DeleteInterp(tcl_interp->interp);
|
15
|
+
Tcl_Release(tcl_interp->interp);
|
16
|
+
free(tcl_interp);
|
17
|
+
}
|
18
|
+
|
19
|
+
static VALUE rb_tcl_interp_send_begin(VALUE args) {
|
20
|
+
VALUE obj = rb_ary_entry(args, 0);
|
21
|
+
VALUE interp_receive_args = rb_ary_entry(args, 1);
|
22
|
+
|
23
|
+
VALUE result = rb_funcall2(obj, rb_intern("interp_receive"), RARRAY(interp_receive_args)->len, RARRAY(interp_receive_args)->ptr);
|
24
|
+
|
25
|
+
tcl_interp_struct *tcl_interp;
|
26
|
+
Data_Get_Struct(obj, tcl_interp_struct, tcl_interp);
|
27
|
+
|
28
|
+
char *tcl_result = strdup(RSTRING(rb_value_to_s(result))->ptr);
|
29
|
+
Tcl_SetResult(tcl_interp->interp, tcl_result, (Tcl_FreeProc *)free);
|
30
|
+
|
31
|
+
return Qtrue;
|
32
|
+
}
|
33
|
+
|
34
|
+
static VALUE rb_tcl_interp_send_rescue(VALUE args, VALUE error_info) {
|
35
|
+
VALUE obj = rb_ary_entry(args, 0);
|
36
|
+
tcl_interp_struct *tcl_interp;
|
37
|
+
Data_Get_Struct(obj, tcl_interp_struct, tcl_interp);
|
38
|
+
|
39
|
+
char *tcl_result = strdup(RSTRING(rb_value_to_s(error_info))->ptr);
|
40
|
+
Tcl_SetResult(tcl_interp->interp, tcl_result, (Tcl_FreeProc *)free);
|
41
|
+
|
42
|
+
if (rb_obj_is_kind_of(error_info, rb_eSystemExit)) {
|
43
|
+
tcl_interp->exit_exception = error_info;
|
44
|
+
}
|
45
|
+
|
46
|
+
return Qfalse;
|
47
|
+
}
|
48
|
+
|
49
|
+
static int rb_tcl_interp_send(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
|
50
|
+
VALUE interp_receive_args = rb_ary_new2(objc - 1);
|
51
|
+
int i;
|
52
|
+
|
53
|
+
for (i = 1; i < objc; i++) {
|
54
|
+
int element_length;
|
55
|
+
const char *element;
|
56
|
+
|
57
|
+
element = Tcl_GetStringFromObj(objv[i], &element_length);
|
58
|
+
rb_ary_push(interp_receive_args, rb_tainted_str_new2(element));
|
59
|
+
}
|
60
|
+
|
61
|
+
VALUE args = rb_ary_new3(2, (VALUE) clientData, interp_receive_args);
|
62
|
+
|
63
|
+
if (rb_rescue2(rb_tcl_interp_send_begin, args, rb_tcl_interp_send_rescue, args, rb_eException) == Qtrue) {
|
64
|
+
return TCL_OK;
|
65
|
+
} else {
|
66
|
+
return TCL_ERROR;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
static VALUE rb_tcl_interp_allocate(VALUE klass) {
|
71
|
+
tcl_interp_struct *tcl_interp;
|
72
|
+
VALUE obj = Data_Make_Struct(klass, tcl_interp_struct, NULL, rb_tcl_interp_destroy, tcl_interp);
|
73
|
+
|
74
|
+
tcl_interp->interp = Tcl_CreateInterp();
|
75
|
+
tcl_interp->exit_exception = Qnil;
|
76
|
+
Tcl_Init(tcl_interp->interp);
|
77
|
+
Tcl_Preserve(tcl_interp->interp);
|
78
|
+
|
79
|
+
Tcl_CreateObjCommand(tcl_interp->interp, "interp_send", (Tcl_ObjCmdProc *)rb_tcl_interp_send, (ClientData) obj, (Tcl_CmdDeleteProc *)NULL);
|
80
|
+
|
81
|
+
return obj;
|
82
|
+
}
|
83
|
+
|
84
|
+
static VALUE rb_tcl_safe_interp_allocate(VALUE klass) {
|
85
|
+
VALUE obj = rb_tcl_interp_allocate(klass);
|
86
|
+
|
87
|
+
tcl_interp_struct *tcl_interp;
|
88
|
+
Data_Get_Struct(obj, tcl_interp_struct, tcl_interp);
|
89
|
+
|
90
|
+
Tcl_MakeSafe(tcl_interp->interp);
|
91
|
+
|
92
|
+
return obj;
|
93
|
+
}
|
94
|
+
|
95
|
+
#ifdef TCL_LIMIT_TIME
|
96
|
+
static VALUE rb_tcl_interp_eval(VALUE self, VALUE args) {
|
97
|
+
VALUE script = rb_ary_entry(args, 0);
|
98
|
+
|
99
|
+
int timeout = 0;
|
100
|
+
if (RARRAY(args)->len == 2) {
|
101
|
+
timeout = NUM2INT(rb_ary_entry(args, 1));
|
102
|
+
}
|
103
|
+
#else
|
104
|
+
static VALUE rb_tcl_interp_eval(VALUE self, VALUE script) {
|
105
|
+
#endif
|
106
|
+
|
107
|
+
tcl_interp_struct *tcl_interp;
|
108
|
+
Data_Get_Struct(self, tcl_interp_struct, tcl_interp);
|
109
|
+
|
110
|
+
#ifdef TCL_LIMIT_TIME
|
111
|
+
if (timeout > 0) {
|
112
|
+
Tcl_Time timeout_time;
|
113
|
+
Tcl_GetTime(&timeout_time);
|
114
|
+
timeout_time.sec += (long) timeout / 1000;
|
115
|
+
timeout_time.usec += (long) (timeout % 1000) * 1000;
|
116
|
+
|
117
|
+
Tcl_LimitSetTime(tcl_interp->interp, &timeout_time);
|
118
|
+
Tcl_LimitTypeSet(tcl_interp->interp, TCL_LIMIT_TIME);
|
119
|
+
}
|
120
|
+
#endif
|
121
|
+
|
122
|
+
int result = Tcl_Eval(tcl_interp->interp, RSTRING(rb_value_to_s(script))->ptr);
|
123
|
+
|
124
|
+
VALUE error_class = rb_const_get(rb_const_get(rb_cObject, rb_intern("Tcl")), rb_intern("Error"));
|
125
|
+
|
126
|
+
#ifdef TCL_LIMIT_TIME
|
127
|
+
if (timeout > 0) {
|
128
|
+
if (Tcl_LimitTypeExceeded(tcl_interp->interp, TCL_LIMIT_TIME))
|
129
|
+
error_class = rb_const_get(rb_const_get(rb_cObject, rb_intern("Tcl")), rb_intern("Timeout"));
|
130
|
+
|
131
|
+
Tcl_LimitTypeReset(tcl_interp->interp, TCL_LIMIT_TIME);
|
132
|
+
}
|
133
|
+
#endif
|
134
|
+
|
135
|
+
switch (result) {
|
136
|
+
case TCL_OK:
|
137
|
+
return rb_tainted_str_new2(tcl_interp->interp->result);
|
138
|
+
case TCL_ERROR:
|
139
|
+
if (NIL_P(tcl_interp->exit_exception)) {
|
140
|
+
rb_raise(error_class, "%s", tcl_interp->interp->result);
|
141
|
+
} else {
|
142
|
+
rb_exit(NUM2INT(rb_iv_get(tcl_interp->exit_exception, "status")));
|
143
|
+
}
|
144
|
+
default:
|
145
|
+
return Qnil;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
static VALUE rb_tcl_interp_list_to_array(VALUE self, VALUE list) {
|
150
|
+
tcl_interp_struct *tcl_interp;
|
151
|
+
Data_Get_Struct(self, tcl_interp_struct, tcl_interp);
|
152
|
+
|
153
|
+
Tcl_Obj *string = Tcl_NewStringObj(RSTRING(rb_value_to_s(list))->ptr, -1);
|
154
|
+
Tcl_IncrRefCount(string);
|
155
|
+
|
156
|
+
int list_length, i;
|
157
|
+
Tcl_Obj **elements;
|
158
|
+
|
159
|
+
if (Tcl_ListObjGetElements(tcl_interp->interp, string, &list_length, &elements) != TCL_OK) {
|
160
|
+
Tcl_DecrRefCount(string);
|
161
|
+
return Qnil;
|
162
|
+
}
|
163
|
+
|
164
|
+
for (i = 0; i < list_length; i++)
|
165
|
+
Tcl_IncrRefCount(elements[i]);
|
166
|
+
|
167
|
+
VALUE result = rb_ary_new2(list_length);
|
168
|
+
|
169
|
+
for (i = 0; i < list_length; i++) {
|
170
|
+
int element_length;
|
171
|
+
const char *element;
|
172
|
+
|
173
|
+
element = Tcl_GetStringFromObj(elements[i], &element_length);
|
174
|
+
rb_ary_push(result, element ? rb_tainted_str_new(element, element_length) : rb_str_new2(""));
|
175
|
+
Tcl_DecrRefCount(elements[i]);
|
176
|
+
}
|
177
|
+
|
178
|
+
Tcl_DecrRefCount(string);
|
179
|
+
|
180
|
+
return result;
|
181
|
+
}
|
182
|
+
|
183
|
+
static VALUE rb_tcl_interp_array_to_list(VALUE self, VALUE array) {
|
184
|
+
tcl_interp_struct *tcl_interp;
|
185
|
+
Data_Get_Struct(self, tcl_interp_struct, tcl_interp);
|
186
|
+
|
187
|
+
int array_length = RARRAY(array)->len, i;
|
188
|
+
|
189
|
+
Tcl_Obj *list = Tcl_NewObj();
|
190
|
+
Tcl_IncrRefCount(list);
|
191
|
+
|
192
|
+
for (i = 0; i < array_length; i++) {
|
193
|
+
VALUE element = rb_ary_entry(array, i);
|
194
|
+
Tcl_Obj *string = Tcl_NewStringObj(RSTRING(rb_value_to_s(element))->ptr, -1);
|
195
|
+
|
196
|
+
Tcl_IncrRefCount(string);
|
197
|
+
Tcl_ListObjAppendElement(tcl_interp->interp, list, string);
|
198
|
+
Tcl_DecrRefCount(string);
|
199
|
+
}
|
200
|
+
|
201
|
+
VALUE result = rb_tainted_str_new2(Tcl_GetStringFromObj(list, NULL));
|
202
|
+
|
203
|
+
Tcl_DecrRefCount(list);
|
204
|
+
|
205
|
+
return result;
|
206
|
+
}
|
207
|
+
|
208
|
+
void Init_tcl_ruby() {
|
209
|
+
VALUE tcl_module = rb_define_module("Tcl");
|
210
|
+
VALUE interp_class = rb_define_class_under(tcl_module, "Interp", rb_cObject);
|
211
|
+
VALUE safe_interp_class = rb_define_class_under(tcl_module, "SafeInterp", interp_class);
|
212
|
+
VALUE error_class = rb_define_class_under(tcl_module, "Error", rb_eStandardError);
|
213
|
+
|
214
|
+
rb_define_alloc_func(interp_class, rb_tcl_interp_allocate);
|
215
|
+
rb_define_alloc_func(safe_interp_class, rb_tcl_safe_interp_allocate);
|
216
|
+
rb_define_method(interp_class, "list_to_array", rb_tcl_interp_list_to_array, 1);
|
217
|
+
rb_define_method(interp_class, "array_to_list", rb_tcl_interp_array_to_list, 1);
|
218
|
+
|
219
|
+
#ifdef TCL_LIMIT_TIME
|
220
|
+
VALUE timeout_class = rb_define_class_under(tcl_module, "Timeout", error_class);
|
221
|
+
rb_define_method(interp_class, "eval", rb_tcl_interp_eval, -2);
|
222
|
+
#else
|
223
|
+
rb_define_method(interp_class, "eval", rb_tcl_interp_eval, 1);
|
224
|
+
#endif
|
225
|
+
}
|
data/lib/.gitignore
ADDED
data/lib/tcl.rb
ADDED
data/lib/tcl/interp.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module Tcl
|
2
|
+
class Interp
|
3
|
+
include InterpHelper
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def load_from_file(filename)
|
7
|
+
interp = new
|
8
|
+
interp.eval(IO.read(filename))
|
9
|
+
interp
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def interp
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def interp_receive(method, *args)
|
18
|
+
send("tcl_#{method}", *args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def expose(name)
|
22
|
+
_!(:interp, :alias, nil, name, nil, :interp_send, name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def proc(name)
|
26
|
+
Tcl::Proc.new(self, name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def var(name)
|
30
|
+
Tcl::Var.find(self, name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def procs
|
34
|
+
list_to_array _!(:info, :procs)
|
35
|
+
end
|
36
|
+
|
37
|
+
def vars
|
38
|
+
list_to_array _!(:info, :vars)
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_tcl
|
42
|
+
%w( var proc ).inject([]) do |lines, type|
|
43
|
+
send("#{type}s").sort.each do |name|
|
44
|
+
object = send(type, name)
|
45
|
+
lines << object.to_tcl unless object.builtin?
|
46
|
+
end
|
47
|
+
lines
|
48
|
+
end.join("\n")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Tcl
|
2
|
+
module InterpHelper
|
3
|
+
def self.included(klass)
|
4
|
+
klass.class_eval do
|
5
|
+
attr_reader :interp
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def _(*args)
|
10
|
+
interp.array_to_list(args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def _!(*args)
|
14
|
+
interp.eval(_(*args))
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(name, *args, &block)
|
18
|
+
if interp.respond_to?(name)
|
19
|
+
interp.send(name, *args, &block)
|
20
|
+
else
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/tcl/proc.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Tcl
|
2
|
+
class Proc
|
3
|
+
BUILTINS = %w(
|
4
|
+
auto_execok auto_import auto_load auto_load_index
|
5
|
+
auto_qualify tclLog unknown
|
6
|
+
)
|
7
|
+
|
8
|
+
include InterpHelper
|
9
|
+
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
def initialize(interp, name)
|
13
|
+
@interp = interp
|
14
|
+
@name = name.to_s
|
15
|
+
to_tcl
|
16
|
+
end
|
17
|
+
|
18
|
+
def arguments
|
19
|
+
list_to_array(_!(:info, :args, name)).map do |argument_name|
|
20
|
+
begin
|
21
|
+
variable_name = "__Tcl_Proc_arguments_#{name}_#{argument_name}"
|
22
|
+
if _!(:info, :default, name, argument_name, variable_name) == "0"
|
23
|
+
argument_name
|
24
|
+
else
|
25
|
+
_(argument_name, var(variable_name).value)
|
26
|
+
end
|
27
|
+
ensure
|
28
|
+
_!(:unset, variable_name)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def body
|
34
|
+
_!(:info, :body, name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(*args)
|
38
|
+
_!(name, *args.map { |arg| arg.to_s })
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_tcl
|
42
|
+
_(:proc, name, _(*arguments), body)
|
43
|
+
end
|
44
|
+
|
45
|
+
def builtin?
|
46
|
+
# TODO should also check to see if the definition has changed
|
47
|
+
BUILTINS.include?(name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/tcl/var.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
module Tcl
|
2
|
+
class Var
|
3
|
+
BUILTINS = %w(
|
4
|
+
auto_index auto_oldpath auto_path env errorCode errorInfo
|
5
|
+
tcl_libPath tcl_library tcl_patchLevel tcl_pkgPath tcl_platform tcl_version
|
6
|
+
)
|
7
|
+
|
8
|
+
include InterpHelper
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def find(interp, name)
|
12
|
+
if interp._!(:array, :exists, name) == "1"
|
13
|
+
ArrayVar.new(interp, name)
|
14
|
+
elsif interp._!(:info, :exists, name) == "1"
|
15
|
+
StringVar.new(interp, name)
|
16
|
+
else
|
17
|
+
raise Tcl::Error, "can't read \"#{name}\": no such variable"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :name
|
23
|
+
|
24
|
+
def initialize(interp, name)
|
25
|
+
@interp = interp
|
26
|
+
@name = name.to_s
|
27
|
+
to_tcl
|
28
|
+
end
|
29
|
+
|
30
|
+
def builtin?
|
31
|
+
BUILTINS.include?(name)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class StringVar < Var
|
36
|
+
def value
|
37
|
+
_!(:set, name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_tcl
|
41
|
+
_(:set, name, value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class ArrayVar < Var
|
46
|
+
def value
|
47
|
+
_!(:array, :get, name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_tcl
|
51
|
+
_(:array, :set, name, value)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), *%w".. lib tcl")
|
4
|
+
|
5
|
+
class ConsoleInterp < Tcl::Interp
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
expose :ruby_eval
|
9
|
+
expose :exit
|
10
|
+
end
|
11
|
+
|
12
|
+
def tcl_ruby_eval(script)
|
13
|
+
Kernel.eval(script)
|
14
|
+
end
|
15
|
+
|
16
|
+
def tcl_exit(code = 0)
|
17
|
+
exit(code.to_i)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
filename = ARGV.shift || File.join(File.dirname(__FILE__), *%w".. .state.dat")
|
22
|
+
interp = ConsoleInterp.load_from_file(filename) rescue ConsoleInterp.new
|
23
|
+
script = ""
|
24
|
+
|
25
|
+
at_exit do
|
26
|
+
File.open(filename, "w") do |file|
|
27
|
+
file.write(interp.to_tcl)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
print ">> "
|
32
|
+
$stdin.each_line do |line|
|
33
|
+
script << line
|
34
|
+
if interp.list_to_array(script)
|
35
|
+
begin
|
36
|
+
result = interp.eval(script)
|
37
|
+
puts result unless result.length.zero?
|
38
|
+
rescue Tcl::Error => e
|
39
|
+
puts "error: #{e}"
|
40
|
+
end
|
41
|
+
script = ""
|
42
|
+
print ">> "
|
43
|
+
else
|
44
|
+
print "?> "
|
45
|
+
end
|
46
|
+
end
|
data/tcl.gemspec
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{tcl}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Sam Stephenson"]
|
12
|
+
s.date = %q{2009-12-01}
|
13
|
+
s.description = %q{A minimal Ruby interface to libtcl}
|
14
|
+
s.email = %q{sstephenson@gmail.com}
|
15
|
+
s.extensions = ["ext/tcl_ruby/extconf.rb"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"LICENSE",
|
18
|
+
"README.rdoc",
|
19
|
+
"TODO"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".gitignore",
|
23
|
+
"LICENSE",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"TODO",
|
27
|
+
"VERSION",
|
28
|
+
"ext/tcl_ruby/extconf.rb",
|
29
|
+
"ext/tcl_ruby/tcl_ruby.c",
|
30
|
+
"lib/.gitignore",
|
31
|
+
"lib/tcl.rb",
|
32
|
+
"lib/tcl/interp.rb",
|
33
|
+
"lib/tcl/interp_helper.rb",
|
34
|
+
"lib/tcl/proc.rb",
|
35
|
+
"lib/tcl/var.rb",
|
36
|
+
"script/console",
|
37
|
+
"tcl.gemspec",
|
38
|
+
"test/fixtures/test.tcl",
|
39
|
+
"test/helper.rb",
|
40
|
+
"test/interp_receive_test.rb",
|
41
|
+
"test/interp_test.rb",
|
42
|
+
"test/proc_test.rb",
|
43
|
+
"test/test_helper.rb",
|
44
|
+
"test/var_test.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/sstephenson/ruby-tcl}
|
47
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.3.5}
|
50
|
+
s.summary = %q{Tcl bindings for Ruby}
|
51
|
+
s.test_files = [
|
52
|
+
"test/helper.rb",
|
53
|
+
"test/interp_receive_test.rb",
|
54
|
+
"test/interp_test.rb",
|
55
|
+
"test/proc_test.rb",
|
56
|
+
"test/test_helper.rb",
|
57
|
+
"test/var_test.rb"
|
58
|
+
]
|
59
|
+
|
60
|
+
if s.respond_to? :specification_version then
|
61
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
62
|
+
s.specification_version = 3
|
63
|
+
|
64
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
65
|
+
else
|
66
|
+
end
|
67
|
+
else
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "test_helper")
|
2
|
+
|
3
|
+
class InterpWithNoReceiveMethod < Tcl::Interp
|
4
|
+
undef_method :interp_receive
|
5
|
+
end
|
6
|
+
|
7
|
+
class InterpWithDefaultReceiveMethod < Tcl::Interp
|
8
|
+
def tcl_no_arguments
|
9
|
+
"hello"
|
10
|
+
end
|
11
|
+
|
12
|
+
def tcl_one_argument(arg)
|
13
|
+
arg
|
14
|
+
end
|
15
|
+
|
16
|
+
def tcl_variable_arguments(*args)
|
17
|
+
_(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def tcl_multiply_by_5(n)
|
21
|
+
n.to_i * 5
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class InterpWithCustomReceiveMethod < Tcl::Interp
|
26
|
+
def interp_receive(method, *args)
|
27
|
+
_(method, *args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class InterpWithExposedMethods < Tcl::Interp
|
32
|
+
def initialize
|
33
|
+
super
|
34
|
+
expose :hello
|
35
|
+
end
|
36
|
+
|
37
|
+
def tcl_hello(who)
|
38
|
+
"hello, #{who}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class InterpWithExitMethod < Tcl::Interp
|
43
|
+
def tcl_exit
|
44
|
+
exit
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class InterpReceiveTest < Test::Unit::TestCase
|
49
|
+
def setup
|
50
|
+
@interp = InterpWithDefaultReceiveMethod.new
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_interp_send_on_interp_with_no_interp_receive_method_should_raise
|
54
|
+
@interp = InterpWithDefaultReceiveMethod.new
|
55
|
+
assert_raises(Tcl::Error) { @interp.eval("interp_send") }
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_interp_send_with_no_arguments_should_raise
|
59
|
+
assert_raises(Tcl::Error) { @interp.eval("interp_send") }
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_interp_send_returns_tcl_ok
|
63
|
+
assert_equal "0", @interp.eval("catch {interp_send no_arguments}")
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_interp_send_to_method_with_no_arguments
|
67
|
+
assert_equal "hello", @interp.eval("interp_send no_arguments")
|
68
|
+
assert_raises(Tcl::Error) { @interp.eval("interp_send no_arguments foo") }
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_interp_send_to_method_with_one_argument
|
72
|
+
assert_raises(Tcl::Error) { @interp.eval("interp_send one_argument") }
|
73
|
+
assert_equal "foo", @interp.eval("interp_send one_argument foo")
|
74
|
+
assert_raises(Tcl::Error) { @interp.eval("interp_send one_argument foo bar") }
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_interp_send_to_method_with_variable_arguments
|
78
|
+
assert_equal "", @interp.eval("interp_send variable_arguments")
|
79
|
+
assert_equal "foo", @interp.eval("interp_send variable_arguments foo")
|
80
|
+
assert_equal "foo bar", @interp.eval("interp_send variable_arguments foo bar")
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_interp_send_converts_non_string_results_to_string
|
84
|
+
assert_equal "0", @interp.eval("interp_send multiply_by_5 0")
|
85
|
+
assert_equal "25", @interp.eval("interp_send multiply_by_5 5")
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_interp_send_with_custom_interp_receive_method
|
89
|
+
@interp = InterpWithCustomReceiveMethod.new
|
90
|
+
assert_raises(Tcl::Error) { @interp.eval("interp_send") }
|
91
|
+
assert_equal "foo", @interp.eval("interp_send foo")
|
92
|
+
assert_equal "foo bar", @interp.eval("interp_send foo bar")
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_interp_expose
|
96
|
+
@interp = InterpWithExposedMethods.new
|
97
|
+
assert_equal "hello, Sam", @interp.eval("interp_send hello Sam")
|
98
|
+
assert_equal "hello, Sam", @interp.eval("hello Sam")
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_interp_send_does_not_convert_system_exit_into_tcl_error
|
102
|
+
@interp = InterpWithExitMethod.new
|
103
|
+
assert_raises(SystemExit) { @interp.eval("interp_send exit") }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
data/test/interp_test.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "test_helper")
|
2
|
+
|
3
|
+
class InterpTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@interp = Tcl::Interp.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_load_from_file
|
9
|
+
vars, procs = @interp.vars, @interp.procs
|
10
|
+
@interp = Tcl::Interp.load_from_file(path_to_fixture("test.tcl"))
|
11
|
+
|
12
|
+
assert_equal ["a", "b"], (@interp.vars - vars).sort
|
13
|
+
assert_equal ["c", "d", "e"], (@interp.procs - procs).sort
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_eval
|
17
|
+
assert_equal "", @interp.eval("")
|
18
|
+
assert_equal "0", @interp.eval("return 0")
|
19
|
+
assert_equal "", @interp.eval("return \"\"")
|
20
|
+
assert_equal "", @interp.eval("return {}")
|
21
|
+
assert_equal " ", @interp.eval("return \" \"")
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_eval_raises_on_tcl_exception
|
25
|
+
assert_raises(Tcl::Error) { @interp.eval("nonexistent") }
|
26
|
+
assert_raises(Tcl::Error) { @interp.eval("{") }
|
27
|
+
assert_raises(Tcl::Error) { @interp.eval("error") }
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_eval_with_timeout_argument
|
31
|
+
if defined?(Tcl::Timeout)
|
32
|
+
assert_raises(Tcl::Timeout) { @interp.eval("while 1 {}", 100) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_array_to_list
|
37
|
+
assert_equal "", @interp.array_to_list([])
|
38
|
+
assert_equal "{}", @interp.array_to_list([nil])
|
39
|
+
assert_equal "{}", @interp.array_to_list([""])
|
40
|
+
assert_equal "one", @interp.array_to_list(["one"])
|
41
|
+
assert_equal "one two", @interp.array_to_list(["one", "two"])
|
42
|
+
assert_equal "a { b} c", @interp.array_to_list(["a", " b", "c"])
|
43
|
+
assert_equal "\\{", @interp.array_to_list(["{"])
|
44
|
+
assert_equal "{\"}", @interp.array_to_list(["\""])
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_list_to_array
|
48
|
+
assert_equal [], @interp.list_to_array("")
|
49
|
+
assert_equal [""], @interp.list_to_array("{}")
|
50
|
+
assert_equal ["one"], @interp.list_to_array("one")
|
51
|
+
assert_equal ["one", "two"], @interp.list_to_array("one two")
|
52
|
+
assert_equal ["a", " b", "c"], @interp.list_to_array("a { b} c")
|
53
|
+
assert_equal ["a", " b", "c"], @interp.list_to_array("a \\ b c")
|
54
|
+
assert_equal ["{"], @interp.list_to_array("\\{")
|
55
|
+
assert_equal ["["], @interp.list_to_array("\\[")
|
56
|
+
assert_equal ["\""], @interp.list_to_array("\\\"")
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_procs
|
60
|
+
@interp.clear!
|
61
|
+
assert_equal [], @interp.procs
|
62
|
+
@interp.eval "proc foo {} {}"
|
63
|
+
assert_equal ["foo"], @interp.procs
|
64
|
+
@interp.eval "proc bar {} {}"
|
65
|
+
assert_equal ["bar", "foo"], @interp.procs.sort
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_vars
|
69
|
+
@interp.clear!
|
70
|
+
assert_equal [], @interp.vars
|
71
|
+
@interp.eval "set a 0"
|
72
|
+
assert_equal ["a"], @interp.vars
|
73
|
+
@interp.eval "set b(a) 0"
|
74
|
+
assert_equal ["a", "b"], @interp.vars.sort
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_proc
|
78
|
+
assert_raises(Tcl::Error) { @interp.proc("foo") }
|
79
|
+
@interp.eval "proc foo {} {}"
|
80
|
+
proc = @interp.proc("foo")
|
81
|
+
assert proc.is_a?(Tcl::Proc)
|
82
|
+
assert_equal "foo", proc.name
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_var
|
86
|
+
assert_raises(Tcl::Error) { @interp.var("foo") }
|
87
|
+
@interp.eval "set foo bar"
|
88
|
+
var = @interp.var("foo")
|
89
|
+
assert var.is_a?(Tcl::Var)
|
90
|
+
assert_equal "foo", var.name
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_to_tcl
|
94
|
+
@interp.eval IO.read(path_to_fixture("test.tcl"))
|
95
|
+
assert_equal <<-EOF.chomp, @interp.to_tcl
|
96
|
+
set a 0
|
97
|
+
array set b {a 1 b 2}
|
98
|
+
proc c args return
|
99
|
+
proc d {a {b 0}} {return $b}
|
100
|
+
proc e {} {}
|
101
|
+
EOF
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_interp_helper_method_missing_super_passthrough
|
105
|
+
assert_raises(NoMethodError) { @interp.nonexistent }
|
106
|
+
end
|
107
|
+
end
|
data/test/proc_test.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "test_helper")
|
2
|
+
|
3
|
+
class ProcTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@interp = Tcl::Interp.load_from_file(path_to_fixture("test.tcl"))
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_proc_arguments_for_proc_with_no_arguments
|
9
|
+
assert_equal [], @interp.proc("e").arguments
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_proc_arguments_for_proc_with_one_argument
|
13
|
+
assert_equal ["args"], @interp.proc("c").arguments
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_proc_arguments_for_proc_with_default_argument
|
17
|
+
assert_equal ["a", "b 0"], @interp.proc("d").arguments
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_proc_body
|
21
|
+
assert_equal "return", @interp.proc("c").body
|
22
|
+
assert_equal "return $b", @interp.proc("d").body
|
23
|
+
assert_equal "", @interp.proc("e").body
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_proc_call
|
27
|
+
assert_equal "", @interp.proc("c").call
|
28
|
+
assert_equal "0", @interp.proc("d").call("a")
|
29
|
+
assert_equal "b", @interp.proc("d").call("a", "b")
|
30
|
+
assert_equal "", @interp.proc("e").call
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_proc_call_raises_on_missing_argument
|
34
|
+
assert_raises(Tcl::Error) { @interp.proc("d").call }
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_proc_to_tcl
|
38
|
+
assert_equal "proc c args return", @interp.proc("c").to_tcl
|
39
|
+
assert_equal "proc d {a {b 0}} {return $b}", @interp.proc("d").to_tcl
|
40
|
+
assert_equal "proc e {} {}", @interp.proc("e").to_tcl
|
41
|
+
end
|
42
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require File.join(File.dirname(__FILE__), *%w".. lib tcl")
|
3
|
+
|
4
|
+
class Tcl::Interp
|
5
|
+
def clear!
|
6
|
+
procs.each { |p| _! :rename, p, "" }
|
7
|
+
vars.each { |v| _! :unset, v }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Test::Unit::TestCase
|
12
|
+
def path_to_fixture(*path_pieces)
|
13
|
+
File.join(File.dirname(__FILE__), "fixtures", *path_pieces)
|
14
|
+
end
|
15
|
+
end
|
data/test/var_test.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "test_helper")
|
2
|
+
|
3
|
+
class VarTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@interp = Tcl::Interp.load_from_file(path_to_fixture("test.tcl"))
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_var_find_raises_when_var_does_not_exist
|
9
|
+
assert_raises(Tcl::Error) { Tcl::Var.find(@interp, "nonexistent") }
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_var_find_returns_string_var
|
13
|
+
var = Tcl::Var.find(@interp, "a")
|
14
|
+
assert_equal "a", var.name
|
15
|
+
assert var.is_a?(Tcl::StringVar)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_var_find_returns_array_var
|
19
|
+
var = Tcl::Var.find(@interp, "b")
|
20
|
+
assert_equal "b", var.name
|
21
|
+
assert var.is_a?(Tcl::ArrayVar)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_string_var_value
|
25
|
+
assert_equal "0", @interp.var("a").value
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_array_var_value
|
29
|
+
assert_equal "a 1 b 2", @interp.var("b").value
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_string_var_to_tcl
|
33
|
+
assert_equal "set a 0", @interp.var("a").to_tcl
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_array_var_to_tcl
|
37
|
+
assert_equal "array set b {a 1 b 2}", @interp.var("b").to_tcl
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_array_var_to_tcl_does_not_modify_errorInfo
|
41
|
+
assert_errorinfo ""
|
42
|
+
Tcl::Var.find(@interp, "b")
|
43
|
+
assert_errorinfo ""
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_attempting_to_find_nonexistent_variable_does_not_modify_errorInfo
|
47
|
+
assert_errorinfo ""
|
48
|
+
assert_raises(Tcl::Error) { Tcl::Var.find(@interp, "nonexistent") }
|
49
|
+
assert_errorinfo ""
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
def assert_errorinfo(value)
|
54
|
+
assert_equal value, @interp.var("errorInfo").value
|
55
|
+
end
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tcl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sam Stephenson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-01 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A minimal Ruby interface to libtcl
|
17
|
+
email: sstephenson@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions:
|
21
|
+
- ext/tcl_ruby/extconf.rb
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.rdoc
|
25
|
+
- TODO
|
26
|
+
files:
|
27
|
+
- .gitignore
|
28
|
+
- LICENSE
|
29
|
+
- README.rdoc
|
30
|
+
- Rakefile
|
31
|
+
- TODO
|
32
|
+
- VERSION
|
33
|
+
- ext/tcl_ruby/extconf.rb
|
34
|
+
- ext/tcl_ruby/tcl_ruby.c
|
35
|
+
- lib/.gitignore
|
36
|
+
- lib/tcl.rb
|
37
|
+
- lib/tcl/interp.rb
|
38
|
+
- lib/tcl/interp_helper.rb
|
39
|
+
- lib/tcl/proc.rb
|
40
|
+
- lib/tcl/var.rb
|
41
|
+
- script/console
|
42
|
+
- tcl.gemspec
|
43
|
+
- test/fixtures/test.tcl
|
44
|
+
- test/helper.rb
|
45
|
+
- test/interp_receive_test.rb
|
46
|
+
- test/interp_test.rb
|
47
|
+
- test/proc_test.rb
|
48
|
+
- test/test_helper.rb
|
49
|
+
- test/var_test.rb
|
50
|
+
has_rdoc: true
|
51
|
+
homepage: http://github.com/sstephenson/ruby-tcl
|
52
|
+
licenses: []
|
53
|
+
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options:
|
56
|
+
- --charset=UTF-8
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.3.5
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Tcl bindings for Ruby
|
78
|
+
test_files:
|
79
|
+
- test/helper.rb
|
80
|
+
- test/interp_receive_test.rb
|
81
|
+
- test/interp_test.rb
|
82
|
+
- test/proc_test.rb
|
83
|
+
- test/test_helper.rb
|
84
|
+
- test/var_test.rb
|