rubypython 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,11 @@
1
+ == 0.2.4 2008-10-24
2
+ * Major Enhancements
3
+ * Provided setter methods for object attributes. Python object attributes can now be set
4
+ from within ruby.
5
+ * Made wrapper classes a subclass of custom made blank object class to try to avoid name
6
+ collisions.
7
+ * Bug Fix
8
+ * Changed part of extconf.rb file that would not work under windows.
1
9
  == 0.2.3 2008-08-29
2
10
  * 2 Major Enhancements
3
11
  * Introduced PyMain object to as a singleton wrapper for the Python __main__ and
data/README.txt CHANGED
@@ -22,7 +22,7 @@
22
22
  RubyPython.stop
23
23
 
24
24
  == REQUIREMENTS:
25
- Python must be installed. Currently, RubyPython requires python2.5 but it may soon be able to work on other platforms. I have only tested it on Mac OSX 10.5, so I'm not sure what parts may need correcting for other systems.
25
+ Python must be installed. Currently, RubyPython requires python2.5 but it may soon be able to work with other versions. It should work fine with Python 2.4 but you may experience issues with lower versions. I have only tested it on Mac OSX 10.5, so I'm not sure what parts may need correcting for other systems.
26
26
 
27
27
  == INSTALL:
28
28
 
@@ -1,13 +1,21 @@
1
1
  require 'mkmf'
2
2
  require 'open3'
3
3
 
4
- if (Open3.popen3("python --version") { |i,o,e| e.read}.chomp.split[1].to_f < 2.4)
5
- puts "I'm sorry you need at least Python 2.4 to use rubypython"
6
- exit -1
4
+ begin
5
+ if (Open3.popen3("python --version") { |i,o,e| e.read}.chomp.split[1].to_f < 2.4)
6
+ puts "I'm sorry you need at least Python 2.4 to use rubypython"
7
+ exit -1
8
+ end
9
+ rescue
10
+ puts "Could not check python version. Do you have Python 2.4 or higher? (y/n)"
11
+ if(gets.chomp == "n")
12
+ puts "Please install Python 2.4 or higher"
13
+ exit
14
+ end
15
+ puts "Okay."
7
16
  end
8
-
9
17
  dir_config("rubypython_bridge")
10
- if(!`which python-config`)
18
+ if(!system("which python-config"))
11
19
  print "Can't configure with python_config"
12
20
  exit -1
13
21
  end
@@ -4,6 +4,30 @@
4
4
  RUBY_EXTERN VALUE mRubyPythonBridge;
5
5
  RUBY_EXTERN VALUE ePythonError;
6
6
 
7
+ VALUE cBlankObject;
8
+
9
+ // :nodoc:
10
+ VALUE blank_undef_if(VALUE mname,VALUE klass)
11
+ {
12
+ if(rb_funcall(mname,rb_intern("match"),1,rb_str_new2("(?:^__)|(?:\\?$)|(?:^send$)|(?:^class$)"))==Qnil)
13
+ {
14
+ rb_undef_method(klass,STR2CSTR(mname));
15
+ return Qtrue;
16
+ }
17
+ else
18
+ {
19
+ return Qfalse;
20
+ }
21
+ }
22
+
23
+ // :nodoc:
24
+ VALUE blank_obj_prep(VALUE self)
25
+ {
26
+ VALUE instance_methods=rb_funcall(self,rb_intern("instance_methods"),0);
27
+ rb_iterate(rb_each,instance_methods,blank_undef_if,self);
28
+ return self;
29
+ }
30
+
7
31
  VALUE cRubyPyObject;
8
32
  VALUE cRubyPyModule;
9
33
  VALUE cRubyPyClass;
@@ -132,6 +156,55 @@ VALUE rp_inst_from_instance(PyObject *pInst)
132
156
  return rInst;
133
157
  }
134
158
 
159
+ VALUE rp_inst_attr_set(VALUE self,VALUE args)
160
+ {
161
+ VALUE name,name_string,rClassDict,result,rInstDict;
162
+ VALUE ret;
163
+ int instance;
164
+ char *cname;
165
+ PObj *pClassDict,*pInstDict,*pDict;
166
+ PyObject *pName;
167
+
168
+ if(!rp_has_attr(self,rb_ary_entry(args,0)))
169
+ {
170
+ int argc;
171
+
172
+ VALUE *argv;
173
+ argc=RARRAY(args)->len;
174
+ argv=ALLOC_N(VALUE,argc);
175
+ MEMCPY(argv,RARRAY(args)->ptr,VALUE,argc);
176
+ return rb_call_super(argc,argv);
177
+ }
178
+ name=rb_ary_shift(args);
179
+ name_string=rb_funcall(name,rb_intern("to_s"),0);
180
+ cname=STR2CSTR(name_string);
181
+ rb_funcall(name_string,rb_intern("chop!"),0);
182
+
183
+ if(NUM2INT(rb_funcall(args,rb_intern("size"),0))==1)
184
+ {
185
+ args=rb_ary_entry(args,0);
186
+ }
187
+
188
+ rClassDict=rb_iv_get(self,"@pclassdict");
189
+ rInstDict=rb_iv_get(self,"@pinstdict");
190
+ Data_Get_Struct(rClassDict,PObj,pClassDict);
191
+ Data_Get_Struct(rInstDict,PObj,pInstDict);
192
+ pName=PyString_FromString(cname);
193
+ if(PyDict_Contains(pInstDict->pObject,pName))
194
+ {
195
+ pDict=pInstDict;
196
+
197
+ }
198
+ else
199
+ {
200
+ pDict=pClassDict;
201
+
202
+ }
203
+ Py_XDECREF(pName);
204
+ PyDict_SetItemString(pDict->pObject,STR2CSTR(name_string),rtop_obj(args,0));
205
+ return Qtrue;
206
+ }
207
+
135
208
  //:nodoc:
136
209
  VALUE rp_inst_delegate(VALUE self,VALUE args)
137
210
  {
@@ -140,6 +213,11 @@ VALUE rp_inst_delegate(VALUE self,VALUE args)
140
213
  char *cname;
141
214
  PObj *pClassDict,*pInstDict;
142
215
  PyObject *pCalled;
216
+
217
+ if(rp_equal(args))
218
+ {
219
+ return rp_inst_attr_set(self,args);
220
+ }
143
221
  if(!rp_has_attr(self,rb_ary_entry(args,0)))
144
222
  {
145
223
  int argc;
@@ -201,6 +279,22 @@ VALUE rp_func_from_function(PyObject *pFunc)
201
279
  return rFunc;
202
280
  }
203
281
 
282
+ VALUE rp_obj_wrap(PyObject* pObj)
283
+ {
284
+ VALUE rObj;
285
+ if(PyFunction_Check(pObj)||PyMethod_Check(pObj)||!PyObject_HasAttrString(pObj,"__dict__"))
286
+ {
287
+ return rp_func_from_function(pObj);
288
+
289
+ }
290
+ if(PyInstance_Check(pObj))
291
+ {
292
+ rObj=rp_inst_from_instance(pObj);
293
+ return rObj;
294
+ }
295
+ return rp_cla_from_class(pObj);
296
+ }
297
+
204
298
  VALUE rp_mod_call_func(VALUE self,VALUE func_name,VALUE args)
205
299
  {
206
300
  PObj *cself;
@@ -268,6 +362,50 @@ VALUE rp_obj_responds(VALUE self,VALUE mname)
268
362
  }
269
363
  return Qfalse;
270
364
  }
365
+
366
+ int rp_equal(VALUE args)
367
+ {
368
+ VALUE mname=rb_ary_entry(args,0);
369
+ VALUE name_string=rb_funcall(mname,rb_intern("to_s"),0);
370
+ return Qtrue==rb_funcall(name_string,rb_intern("end_with?"),1,rb_str_new2("="));
371
+ }
372
+
373
+
374
+
375
+ int rp_double_bang(VALUE args)
376
+ {
377
+ VALUE mname=rb_ary_entry(args,0);
378
+ VALUE name_string=rb_funcall(mname,rb_intern("to_s"),0);
379
+ return Qtrue==rb_funcall(name_string,rb_intern("end_with?"),1,rb_str_new2("!!"));
380
+ }
381
+
382
+ VALUE rp_mod_attr_set(VALUE self,VALUE args)
383
+ {
384
+ VALUE rDict;
385
+ PObj *pDict;
386
+ VALUE mname=rb_ary_shift(args);
387
+ VALUE name_string=rb_funcall(mname,rb_intern("to_s"),0);
388
+ rb_funcall(name_string,rb_intern("chop!"),0);
389
+ if(!rp_has_attr(self,name_string))
390
+ {
391
+ int argc;
392
+
393
+ VALUE *argv;
394
+ argc=RARRAY(args)->len;
395
+ argv=ALLOC_N(VALUE,argc);
396
+ MEMCPY(argv,RARRAY(args)->ptr,VALUE,argc);
397
+ return rb_call_super(argc,argv);
398
+ }
399
+ if(NUM2INT(rb_funcall(args,rb_intern("size"),0))==1)
400
+ {
401
+ args=rb_ary_entry(args,0);
402
+ }
403
+ rDict=rb_iv_get(self,"@pdict");
404
+ Data_Get_Struct(rDict,PObj,pDict);
405
+ PyDict_SetItemString(pDict->pObject,STR2CSTR(name_string),rtop_obj(args,0));
406
+ return Qtrue;
407
+ }
408
+
271
409
  //:nodoc:
272
410
  VALUE rp_mod_delegate(VALUE self,VALUE args)
273
411
  {
@@ -275,6 +413,14 @@ VALUE rp_mod_delegate(VALUE self,VALUE args)
275
413
  VALUE ret;
276
414
  PObj *pDict;
277
415
  PyObject *pCalled;
416
+ if(rp_equal(args))
417
+ {
418
+ return rp_mod_attr_set(self,args);
419
+ }
420
+ // if(rp_double_bang)
421
+ // {
422
+ // return rp_mod_attr_db(args);
423
+ // }
278
424
  if(!rp_has_attr(self,rb_ary_entry(args,0)))
279
425
  {
280
426
  int argc;
@@ -307,6 +453,13 @@ VALUE rp_mod_delegate(VALUE self,VALUE args)
307
453
 
308
454
  }
309
455
 
456
+ // :nodoc:
457
+ inline void Init_BlankObject()
458
+ {
459
+ cBlankObject=rb_define_class_under(mRubyPythonBridge,"BlankObject",rb_cObject);
460
+ blank_obj_prep(cBlankObject);
461
+ }
462
+
310
463
  /*
311
464
  A wrapper class for Python objects that allows them to manipulated from within ruby.
312
465
 
@@ -316,7 +469,7 @@ classes which wrap Python objects of similar names.
316
469
  */
317
470
  inline void Init_RubyPyObject()
318
471
  {
319
- cRubyPyObject=rb_define_class_under(mRubyPythonBridge,"RubyPyObject",rb_cObject);
472
+ cRubyPyObject=rb_define_class_under(mRubyPythonBridge,"RubyPyObject",cBlankObject);
320
473
  rb_define_alloc_func(cRubyPyObject,rp_obj_alloc);
321
474
  rb_define_method(cRubyPyObject,"free_pobj",rp_obj_free_pobj,0);
322
475
  rb_define_method(cRubyPyObject,"__name",rp_obj_name,0);
@@ -51,5 +51,18 @@ VALUE rp_cla_new_inst(VALUE self,VALUE args);
51
51
 
52
52
  VALUE rp_obj_responds(VALUE self,VALUE mname);
53
53
 
54
+ VALUE blank_undef_if(VALUE mname,VALUE klass);
55
+
56
+ VALUE blank_obj_prep(VALUE self);
57
+
58
+ int rp_equal(VALUE args);
59
+
60
+ int rp_double_bang(VALUE args);
61
+
62
+ VALUE rp_mod_attr_set(VALUE self,VALUE args);
63
+
64
+ VALUE rp_inst_attr_set(VALUE self, VALUE args);
65
+
66
+ VALUE rp_obj_wrap(PyObject* pObj);
54
67
 
55
68
  #endif /* _RP_OBJECT_H_ */
@@ -1,6 +1,7 @@
1
1
  #include "rtop.h"
2
2
 
3
3
  RUBY_EXTERN VALUE cRubyPyObject;
4
+ RUBY_EXTERN PyObject* rp_obj_pobject(VALUE self);
4
5
 
5
6
  PyObject* rtop_string(VALUE rString)
6
7
  {
@@ -4,6 +4,7 @@ VALUE mRubyPythonBridge;
4
4
  RUBY_EXTERN VALUE cRubyPyObject;
5
5
  RUBY_EXTERN VALUE cRubyPyModule;
6
6
  RUBY_EXTERN VALUE cRubyPyClass;
7
+ RUBY_EXTERN VALUE cBlankObject;
7
8
 
8
9
 
9
10
  /*
@@ -84,6 +85,7 @@ void Init_rubypython_bridge()
84
85
  rb_define_module_function(mRubyPythonBridge,"start",rp_start,0);
85
86
  rb_define_module_function(mRubyPythonBridge,"stop",rp_stop,0);
86
87
  rb_define_module_function(mRubyPythonBridge,"import",rp_import,1);
88
+ Init_BlankObject();
87
89
  Init_RubyPyObject();
88
90
  Init_RubyPyModule();
89
91
  Init_RubyPyClass();
@@ -2,7 +2,7 @@ module RubyPython
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 2
5
- TINY = 3
5
+ TINY = 4
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -15,8 +15,9 @@ end
15
15
  # The PyMainClass object provides somewhat experimental block support.
16
16
  # A block may be passed to a method call and the object returned by the function call
17
17
  # will be passed as an argument to the block.
18
- class PyMainClass
18
+ class PyMainClass < RubyPythonBridge::BlankObject
19
19
  include Singleton
20
+ attr_writer :main, :builtin
20
21
  #:nodoc:
21
22
  def main
22
23
  @main||=RubyPython.import "__main__"
@@ -41,6 +42,7 @@ class PyMainClass
41
42
  if(block)
42
43
  return block.call(result)
43
44
  end
45
+ result
44
46
  end
45
47
  end
46
48
 
data/lib/rubypython.rb CHANGED
@@ -30,6 +30,33 @@ This allows one to do something like the following:
30
30
  puts cPickle.dumps "RubyPython is still awesome!"
31
31
  end
32
32
 
33
+ The downside to the above method is that the block has no access to the encompassing scope. An
34
+ alternative is to use <tt>RubyPython.session</tt>. The downside to this approach is that the module
35
+ methods are not available by their unqualified names: i.e.
36
+ irb(main):001:0> RubyPython.session do
37
+ irb(main):002:1* cPickle=import "cPickle"
38
+ irb(main):003:1> end
39
+ NoMethodError: undefined method `import' for main:Object
40
+ from (irb):2
41
+ from ./rubypython.rb:93:in `call'
42
+ from ./rubypython.rb:93:in `session'
43
+ from (irb):1
44
+
45
+ However:
46
+ irb(main):001:0> RubyPython.session do
47
+ irb(main):002:1* cPickle=RubyPython.import "cPickle"
48
+ irb(main):003:1> puts cPickle.dumps "RubyPython is still awesome!"
49
+ irb(main):004:1> end
50
+ S'RubyPython is still awesome!'
51
+ .
52
+ => nil
53
+
54
+ A compromise can be achieved by just including the RubyPython module into the scope you're
55
+ working in.
56
+
57
+ If you really wish to be free of dealing with the interpreter, just import 'rubypython/session'.
58
+ This will start the interpreter on import and will halt it when execution ends.
59
+
33
60
  ==Errors
34
61
  The RubyPythonModule defines a new error object, PythonError. Should any error occur within
35
62
  the Python interpreter, the class and value of the error will be passed back into ruby within
@@ -64,6 +91,8 @@ module RubyPython
64
91
  ObjectSpace.each_object(RubyPythonBridge::RubyPyObject) do |o|
65
92
  o.free_pobj
66
93
  end
94
+ PyMain.main=nil
95
+ PyMain.builtin=nil
67
96
  RubyPythonBridge.stop
68
97
  end
69
98
 
@@ -74,11 +103,24 @@ module RubyPython
74
103
 
75
104
  # Handles the setup and cleanup involved with using the interpreter for you.
76
105
  # Note that all Python object will be effectively scope to within the block
77
- # as the embedded interpreter will be halted at its end.
106
+ # as the embedded interpreter will be halted at its end. The supplied block is
107
+ # run within the scope of the RubyPython module.
108
+ #
109
+ # Alternatively the user may prefer RubyPython.session which simples handles
110
+ # initialization and cleanup of the interpreter.
78
111
  def self.run(&block)
79
112
  start
80
113
  module_eval(&block)
81
114
  stop
82
115
  end
116
+
117
+ # Simply starts the interpreter, runs the supplied block, and stops the interpreter.
118
+ def self.session(&block)
119
+ start
120
+ retval=block.call
121
+ stop
122
+ return retval
123
+ end
124
+ end
125
+
83
126
 
84
- end
@@ -5,13 +5,14 @@ class TestRubypython < Test::Unit::TestCase
5
5
  def setup
6
6
  end
7
7
 
8
+
8
9
  def test_simple
9
10
  assert RubyPython.start
10
11
  assert RubyPython.import "urllib"
11
12
  assert(RubyPython.stop)
12
13
  assert(!RubyPython.stop)
13
14
  end
14
-
15
+
15
16
  def test_delegation
16
17
  RubyPython.start
17
18
  cPickle=RubyPython.import("cPickle")
@@ -29,14 +30,14 @@ class TestRubypython < Test::Unit::TestCase
29
30
  end
30
31
  assert(RubyPython.stop)
31
32
  end
32
-
33
+
33
34
  def test_two_imports
34
35
  RubyPython.start
35
36
  RubyPython.import "cPickle"
36
37
  RubyPython.import "urllib"
37
38
  RubyPython.stop
38
39
  end
39
-
40
+
40
41
  def test_propogate_python_errror
41
42
  RubyPython.start
42
43
  assert_raise PythonError do
@@ -44,7 +45,7 @@ class TestRubypython < Test::Unit::TestCase
44
45
  end
45
46
  RubyPython.stop
46
47
  end
47
-
48
+
48
49
  def test_run_method
49
50
  unpickled=nil
50
51
  RubyPython.run do
@@ -55,7 +56,7 @@ class TestRubypython < Test::Unit::TestCase
55
56
  assert_equal(unpickled,{"a"=>"n", [1, "2"]=>4})
56
57
  assert(!RubyPython.stop)
57
58
  end
58
-
59
+
59
60
  def test_instance_method_delegation
60
61
  RubyPython.start
61
62
  wave=RubyPython.import "wave"
@@ -64,4 +65,44 @@ class TestRubypython < Test::Unit::TestCase
64
65
  w.close
65
66
  RubyPython.stop
66
67
  end
68
+
69
+ def test_pymain_delegation
70
+ RubyPython.start
71
+ assert_equal(PyMain.float(42),42.to_f)
72
+ RubyPython.stop
73
+ end
74
+
75
+ def test_block_syntax
76
+ returned=""
77
+ RubyPython.start
78
+ returned=PyMain.float(22) do |f|
79
+ f*2
80
+ end
81
+ assert_equal(returned,44.0)
82
+ RubyPython.stop
83
+ end
84
+
85
+ def test_session_function
86
+ RubyPython.session do
87
+ cPickle=RubyPython.import "cPickle"
88
+ cPickle.inspect
89
+ assert_equal(cPickle.loads("(dp1\nS'a'\nS'n'\ns(I1\nS'2'\ntp2\nI4\ns."),{"a"=>"n", [1, "2"]=>4})
90
+ end
91
+ end
92
+
93
+
94
+ def test_setter_ary
95
+ RubyPython.session do
96
+ sys=RubyPython.import 'sys'
97
+ sys.path=[""]
98
+ assert_equal([""],sys.path)
99
+ end
100
+ end
101
+
102
+ def test_setter_instance
103
+ RubyPython.session do
104
+
105
+ end
106
+ end
107
+
67
108
  end
@@ -0,0 +1,6 @@
1
+ class TestSessionImport < Test::Unit::TestCase
2
+ def test_session
3
+ require 'rubypython/session'
4
+ assert RubyPython.import "cPickle"
5
+ end
6
+ end
data/website/index.html CHANGED
@@ -33,7 +33,7 @@
33
33
  <h1>rubypython</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/rubypython"; return false'>
35
35
  <p>Get Version</p>
36
- <a href="http://rubyforge.org/projects/rubypython" class="numbers">0.2.3</a>
36
+ <a href="http://rubyforge.org/projects/rubypython" class="numbers">0.2.4</a>
37
37
  </div>
38
38
  <h2>What</h2>
39
39
  <p>RubyPython is a C bridge between Ruby and Python with a Ruby interface. It&#8217;s aim is to make the power of the Python&#8217;s great standard library available to Ruby programmers from within Ruby.<br />
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubypython
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Raines
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-08-29 00:00:00 -04:00
12
+ date: 2008-10-24 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -113,3 +113,4 @@ test_files:
113
113
  - test/test_helper.rb
114
114
  - test/test_rubypython.rb
115
115
  - test/test_rubypython_bridge_extn.rb
116
+ - test/test_session.rb