phuby 1.0.0

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.
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
@@ -0,0 +1,6 @@
1
+ === 1.0.0 / 2009-07-31
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
@@ -0,0 +1,35 @@
1
+ .autotest
2
+ CHANGELOG.rdoc
3
+ Manifest.txt
4
+ README.rdoc
5
+ Rakefile
6
+ bin/phrack
7
+ bin/phuby
8
+ bin/phuby_server
9
+ ext/phuby/extconf.rb
10
+ ext/phuby/phuby.c
11
+ ext/phuby/phuby.h
12
+ ext/phuby/phuby_array.c
13
+ ext/phuby/phuby_array.h
14
+ ext/phuby/phuby_conversions.c
15
+ ext/phuby/phuby_conversions.h
16
+ ext/phuby/phuby_runtime.c
17
+ ext/phuby/phuby_runtime.h
18
+ lib/phuby.rb
19
+ lib/phuby/array.rb
20
+ lib/phuby/events.rb
21
+ lib/phuby/php_handler.rb
22
+ lib/phuby/rails.rb
23
+ lib/phuby/runtime.rb
24
+ php.patch
25
+ test/assets/hello_world.php
26
+ test/assets/htdocs/index.php
27
+ test/helper.rb
28
+ test/test_array.rb
29
+ test/test_handlers.rb
30
+ test/test_header_sent.rb
31
+ test/test_nil.rb
32
+ test/test_object.rb
33
+ test/test_php_handler.rb
34
+ test/test_phuby.rb
35
+ test/test_runtime.rb
@@ -0,0 +1,96 @@
1
+ = phuby
2
+
3
+ * http://github.com/tenderlove/phuby
4
+
5
+ == DESCRIPTION:
6
+
7
+ Phuby wraps PHP in a loving embrace. Exposes a PHP runtime in ruby
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * many
12
+
13
+ == SYNOPSIS:
14
+
15
+ rt = Phuby::Runtime.new
16
+ rt.start
17
+
18
+ rt.eval('$hello = "world"')
19
+ assert_equal "world", rt['hello']
20
+
21
+ rt.stop
22
+
23
+ == REQUIREMENTS:
24
+
25
+ * php
26
+
27
+ == BUILD INSTRUCTIONS:
28
+
29
+ * Download php-5.3.0
30
+
31
+ The following instructions apply to OS X (probably not needed on linux):
32
+
33
+ DO NOT change the prefix... No, I don't know why yet.
34
+
35
+ === Install iconv with macports
36
+
37
+ $ sudo port install iconv
38
+
39
+ === Install MySQL with macports
40
+
41
+ $ sudo port install mysql5 mysql5-server
42
+
43
+ Set some symbolic links:
44
+
45
+ $ cd /opt/local
46
+ $ sudo ln -s mysql5/mysql include/mysql
47
+ $ sudo ln -s mysql5/mysql/libmysqlclient.15.dylib lib/libmysqlclient.dylib
48
+
49
+ === Patch and configure php
50
+
51
+ If you're on OS X, apply php.patch to the downloaded php. Then configure
52
+ php with the proper flags. These paths are for OS X, but you should be able
53
+ to adjust them for linux:
54
+
55
+ $ patch -p0 < ../path/to/php.patch
56
+
57
+ $ ./configure --enable-debug \
58
+ --enable-embed \
59
+ --disable-cli \
60
+ --with-mysql=/opt/local \
61
+ --with-mysqli=/opt/local/lib/mysql5/bin/mysql_config \
62
+ --with-mysql-sock=/opt/local/var/run/mysql5/mysqld.sock \
63
+ --prefix=/usr/local
64
+
65
+ $ make && sudo make install
66
+
67
+ Then, either install the gem, or rake test
68
+
69
+ == INSTALL:
70
+
71
+ * No.
72
+
73
+ == LICENSE:
74
+
75
+ (The MIT License)
76
+
77
+ Copyright (c) Aaron Patterson and Ryan Davis of Seattle.rb
78
+
79
+ Permission is hereby granted, free of charge, to any person obtaining
80
+ a copy of this software and associated documentation files (the
81
+ 'Software'), to deal in the Software without restriction, including
82
+ without limitation the rights to use, copy, modify, merge, publish,
83
+ distribute, sublicense, and/or sell copies of the Software, and to
84
+ permit persons to whom the Software is furnished to do so, subject to
85
+ the following conditions:
86
+
87
+ The above copyright notice and this permission notice shall be
88
+ included in all copies or substantial portions of the Software.
89
+
90
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
91
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
92
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
93
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
94
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
95
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
96
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ gem 'rake-compiler', '>= 0.4.1'
6
+ require "rake/extensiontask"
7
+
8
+ HOE = Hoe.spec 'phuby' do
9
+ developer('Aaron Patterson', 'aaronp@rubyforge.org')
10
+ self.readme_file = 'README.rdoc'
11
+ self.history_file = 'CHANGELOG.rdoc'
12
+ self.extra_rdoc_files = FileList['*.rdoc']
13
+
14
+ self.spec_extras = { :extensions => ["ext/phuby/extconf.rb"] }
15
+ end
16
+
17
+ RET = Rake::ExtensionTask.new("phuby", HOE.spec) do |ext|
18
+ ext.lib_dir = File.join('lib', 'phuby')
19
+ end
20
+
21
+ Rake::Task[:test].prerequisites << :compile
22
+
23
+ # vim: syntax=ruby
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'phuby'
5
+ require 'rack'
6
+
7
+ ##
8
+ # Rack::Phrack is a Rack handler that will evaulate and serve PHP files.
9
+
10
+ class Rack::Phrack < Rack::File
11
+ class Events < Struct.new(:code, :headers, :body)
12
+ def write string; body << string; end
13
+ def send_headers response_code; end
14
+
15
+ def header value, op
16
+ k, v = value.split(': ', 2)
17
+ self.code = 302 if k == 'Location'
18
+ headers[k] = [headers[k], Rack::Utils.unescape(v)].compact.join "\n"
19
+ end
20
+ end
21
+
22
+ def call env
23
+ events = Events.new 200, {}, ''
24
+ file = File.join @root, env['PATH_INFO']
25
+ file = File.join file, "index.php" if File.directory?(file)
26
+
27
+ return super unless file =~ /php$/
28
+
29
+ Dir.chdir(File.dirname(file)) do
30
+ Phuby::Runtime.php do |rt|
31
+ rt.eval "date_default_timezone_set('America/Los_Angeles');" # *shrug*
32
+
33
+ { Rack::Utils.parse_query(env['QUERY_STRING']) => "_GET",
34
+ Rack::Utils.parse_query(env['rack.input'].read) => "_POST",
35
+ Rack::Utils.parse_query(env['HTTP_COOKIE'], ';') => "_COOKIE",
36
+ }.each do |from, to|
37
+ from.each { |k,v| rt[to][k] = v }
38
+ end
39
+
40
+ env.each { |k,v| rt['_SERVER'][k] = v || '' unless k =~ /^rack/ }
41
+ rt["_SERVER"]['REQUEST_URI'] = env['PATH_INFO']
42
+
43
+ rt.with_events(events) { open(file) { |f| rt.eval f } } # RUN!
44
+ end
45
+ end
46
+ events.to_a
47
+ end
48
+ end
49
+
50
+ Rack::Handler::WEBrick.run(Rack::Phrack.new(ARGV[0] || Dir.pwd), :Port => 10101)
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ abort "you need to write me"
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'phuby'
5
+ require 'webrick'
6
+
7
+ s = WEBrick::HTTPServer.new(:Port => 10101, :DocumentRoot => ARGV[0])
8
+
9
+ s.mount('/', Phuby::PHPHandler)
10
+
11
+ trap('INT') { s.shutdown }
12
+ s.start
@@ -0,0 +1,24 @@
1
+ ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
2
+
3
+ # :stopdoc:
4
+
5
+ require 'mkmf'
6
+
7
+ config = Dir["/{usr,opt}/local/bin/php-config"]
8
+ prefix = `#{config} --prefix`.chomp
9
+
10
+ php_inc, php_lib = dir_config("php5", "#{prefix}/include", "#{prefix}/lib")
11
+
12
+ $INCFLAGS = "-I#{File.join(php_inc, "php").quote} #{$INCFLAGS}"
13
+
14
+ %w{ Zend TSRM main }.each do |dir|
15
+ $INCFLAGS = "-I#{File.join(php_inc, "php", dir).quote} #{$INCFLAGS}"
16
+ end
17
+
18
+ unless find_library("php5", "php_embed_init", php_lib)
19
+ abort "php is missing!"
20
+ end
21
+
22
+ create_makefile("phuby/phuby")
23
+
24
+ # :startdoc:
@@ -0,0 +1,11 @@
1
+ #include <phuby.h>
2
+
3
+ VALUE mPhuby;
4
+
5
+ void Init_phuby()
6
+ {
7
+ mPhuby = rb_define_module("Phuby");
8
+
9
+ init_phuby_runtime();
10
+ init_phuby_array();
11
+ }
@@ -0,0 +1,14 @@
1
+ #ifndef PHUBY
2
+ #define PHUBY
3
+
4
+ #include <stdlib.h>
5
+ #include <ruby.h>
6
+ #include <sapi/embed/php_embed.h>
7
+
8
+ #include <phuby_conversions.h>
9
+ #include <phuby_runtime.h>
10
+ #include <phuby_array.h>
11
+
12
+ extern VALUE mPhuby;
13
+
14
+ #endif
@@ -0,0 +1,92 @@
1
+ #include <phuby.h>
2
+
3
+ VALUE cPhubyArray;
4
+
5
+ VALUE Data_Wrap_PhubyArray(VALUE rt, zval * value)
6
+ {
7
+ VALUE arry = Data_Wrap_Struct(cPhubyArray, 0, 0, value);
8
+ rb_iv_set(arry, "@runtime", rt);
9
+ return arry;
10
+ }
11
+
12
+ static VALUE length(VALUE self)
13
+ {
14
+ zval * array;
15
+
16
+ Data_Get_Struct(self, zval, array);
17
+
18
+ return INT2NUM(zend_hash_num_elements(Z_ARRVAL_P(array)));
19
+ }
20
+
21
+ static VALUE get(VALUE self, VALUE key)
22
+ {
23
+ zval * array;
24
+ zval **value;
25
+
26
+ Data_Get_Struct(self, zval, array);
27
+
28
+ switch(TYPE(key))
29
+ {
30
+ case T_FIXNUM:
31
+ if(SUCCESS == zend_hash_index_find(
32
+ Z_ARRVAL_P(array),
33
+ NUM2INT(key),
34
+ (void **)&value
35
+ )) {
36
+ return ZVAL2VALUE(rb_iv_get(self, "@runtime"), *value);
37
+ }
38
+ break;
39
+ default:
40
+ if(SUCCESS == zend_hash_find(
41
+ Z_ARRVAL_P(array),
42
+ StringValuePtr(key),
43
+ RSTRING_LEN(key) + 1, // Add one for the NULL byte
44
+ (void **)&value
45
+ )) {
46
+ return ZVAL2VALUE(rb_iv_get(self, "@runtime"), *value);
47
+ }
48
+ }
49
+
50
+ return Qnil;
51
+ }
52
+
53
+ static VALUE set(VALUE self, VALUE key, VALUE value)
54
+ {
55
+ zval * array;
56
+
57
+ Data_Get_Struct(self, zval, array);
58
+
59
+ VALUE s_key = rb_funcall(key, rb_intern("to_s"), 0);
60
+
61
+ add_assoc_zval(array,
62
+ StringValuePtr(s_key),
63
+ VALUE2ZVAL(rb_iv_get(self, "@runtime"), value)
64
+ );
65
+
66
+ return self;
67
+ }
68
+
69
+ static VALUE key_eh(VALUE self, VALUE key)
70
+ {
71
+ zval * array;
72
+ zval **value;
73
+
74
+ Data_Get_Struct(self, zval, array);
75
+
76
+ if(zend_hash_exists(Z_ARRVAL_P(array),
77
+ StringValuePtr(key), RSTRING_LEN(key) + 1)) {
78
+ return Qtrue;
79
+ }
80
+
81
+ return Qfalse;
82
+ }
83
+
84
+ void init_phuby_array()
85
+ {
86
+ cPhubyArray = rb_define_class_under(mPhuby, "Array", rb_cObject);
87
+
88
+ rb_define_method(cPhubyArray, "length", length, 0);
89
+ rb_define_method(cPhubyArray, "get", get, 1);
90
+ rb_define_method(cPhubyArray, "set", set, 2);
91
+ rb_define_method(cPhubyArray, "key?", key_eh, 1);
92
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef PHUBY_ARRAY
2
+ #define PHUBY_ARRAY
3
+
4
+ extern VALUE cPhubyArray;
5
+
6
+ void init_phuby_array();
7
+ VALUE Data_Wrap_PhubyArray(VALUE rt, zval * value);
8
+
9
+ #endif
@@ -0,0 +1,92 @@
1
+ #include <phuby.h>
2
+
3
+ zval * Phuby_value_to_zval(VALUE rt, VALUE value)
4
+ {
5
+ zval *php_value;
6
+
7
+ MAKE_STD_ZVAL(php_value);
8
+
9
+ switch(TYPE(value))
10
+ {
11
+ case T_FIXNUM:
12
+ ZVAL_LONG(php_value, NUM2INT(value));
13
+ break;
14
+
15
+ case T_TRUE:
16
+ case T_FALSE:
17
+ ZVAL_BOOL(php_value, value == Qtrue ? 1 : 0);
18
+ break;
19
+
20
+ case T_FLOAT:
21
+ case T_BIGNUM:
22
+ ZVAL_DOUBLE(php_value, NUM2DBL(value));
23
+ break;
24
+
25
+ case T_STRING:
26
+ ZVAL_STRINGL(php_value, StringValuePtr(value), RSTRING_LEN(value), 1);
27
+ break;
28
+ case T_OBJECT:
29
+ case T_DATA:
30
+ {
31
+ object_init_ex(php_value, php_ruby_proxy);
32
+ VALUE map = rb_iv_get(rt, "@proxy_map");
33
+ rb_hash_aset(map, INT2NUM((int)php_value), value);
34
+ }
35
+ break;
36
+ case T_ARRAY:
37
+ {
38
+ array_init(php_value);
39
+ int i;
40
+ for(i = 0; i < RARRAY_LEN(value); i++) {
41
+ VALUE key = rb_funcall(INT2NUM(i), rb_intern("to_s"), 0);
42
+ VALUE thing = RARRAY_PTR(value)[i];
43
+ add_assoc_zval(php_value, StringValuePtr(key), Phuby_value_to_zval(rt, thing));
44
+ }
45
+ VALUE map = rb_iv_get(rt, "@proxy_map");
46
+ rb_hash_aset(map, INT2NUM((int)php_value), value);
47
+ }
48
+ break;
49
+ case T_NIL:
50
+ ZVAL_NULL(php_value);
51
+ break;
52
+ default:
53
+ rb_raise(rb_eRuntimeError, "Can't convert ruby object: %s %d", rb_class2name(CLASS_OF(value)), TYPE(value));
54
+ }
55
+
56
+ return php_value;
57
+ }
58
+
59
+ VALUE Phuby_zval_to_value(VALUE rt, zval * value)
60
+ {
61
+ switch(Z_TYPE_P(value)) {
62
+ case IS_NULL:
63
+ return Qnil;
64
+ break;
65
+ case IS_BOOL:
66
+ if(Z_BVAL_P(value))
67
+ return Qtrue;
68
+ else
69
+ return Qfalse;
70
+ break;
71
+ case IS_LONG:
72
+ return INT2NUM(Z_LVAL_P(value));
73
+ break;
74
+ case IS_DOUBLE:
75
+ return rb_float_new(Z_DVAL_P(value));
76
+ break;
77
+ case IS_STRING:
78
+ return rb_str_new(Z_STRVAL_P(value), Z_STRLEN_P(value));
79
+ break;
80
+ case IS_ARRAY:
81
+ return Data_Wrap_PhubyArray(rt, value);
82
+ break;
83
+ case IS_OBJECT:
84
+ {
85
+ VALUE map = rb_iv_get(rt, "@proxy_map");
86
+ return rb_hash_aref(map, INT2NUM((int)value));
87
+ }
88
+ default:
89
+ rb_raise(rb_eRuntimeError, "Whoa, I don't know how to convert that");
90
+ }
91
+ }
92
+