diff options
Diffstat (limited to 'web/server/h2o/libh2o/deps/mruby-require')
13 files changed, 722 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/deps/mruby-require/.gitignore b/web/server/h2o/libh2o/deps/mruby-require/.gitignore new file mode 100644 index 000000000..ceeb05b41 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/.gitignore @@ -0,0 +1 @@ +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-require/.travis.yml b/web/server/h2o/libh2o/deps/mruby-require/.travis.yml new file mode 100644 index 000000000..ffe227284 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-require/README.md b/web/server/h2o/libh2o/deps/mruby-require/README.md new file mode 100644 index 000000000..70818ffba --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/README.md @@ -0,0 +1,59 @@ +mruby-require +============= + +"mruby-require" is a mrbgem, provides +[require](http://docs.ruby-lang.org/ja/2.0.0/class/Kernel.html#M_REQUIRE) and +[load](http://docs.ruby-lang.org/ja/2.0.0/class/Kernel.html#M_LOAD) for mruby. + +### Example: + +```Ruby +# a.rb + +require "b" + +b = Bclass.new +p b.method +``` +```Ruby +# b.rb + +class Bclass + def method + "BBB" + end +end +``` +```sh +% mruby a.rb +"BBB" +``` + + +### To run the tests: + + ruby run_test.rb + + +## License + +Copyright (c) 2013 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/web/server/h2o/libh2o/deps/mruby-require/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-require/mrbgem.rake new file mode 100644 index 000000000..e95cdb8ca --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/mrbgem.rake @@ -0,0 +1,15 @@ +MRuby::Gem::Specification.new('mruby-require') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan Inc.' + + spec.add_dependency 'mruby-array-ext' + spec.add_dependency 'mruby-dir' + spec.add_dependency 'mruby-io' +# only used for testing? +# spec.add_dependency 'mruby-tempfile' + spec.add_dependency 'mruby-time' + spec.add_dependency 'mruby-eval' + + spec.cc.include_paths << "#{build.root}/src" +end + diff --git a/web/server/h2o/libh2o/deps/mruby-require/mrblib/require.rb b/web/server/h2o/libh2o/deps/mruby-require/mrblib/require.rb new file mode 100644 index 000000000..cdf25ace3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/mrblib/require.rb @@ -0,0 +1,97 @@ +class LoadError < ScriptError; end + +begin + eval "1", nil + def _require_eval_load(*args) + self.eval(*args) + end +rescue ArgumentError + def _require_eval_load(*args) + self.eval(args[0]) + end +end + +module Kernel + def load(path) + raise TypeError unless path.class == String + + if File.exist?(path) && File.extname(path) == ".mrb" + _load_mrb_file path + elsif File.exist?(path) + # _load_rb_str File.open(path).read.to_s, path + _require_eval_load File.open(path).read.to_s, nil, path + else + raise LoadError.new "File not found -- #{path}" + end + + true + end + + def require(path) + raise TypeError unless path.class == String + + # require method can load .rb, .mrb or without-ext filename only. + unless ["", ".rb", ".mrb"].include? File.extname(path) + raise LoadError.new "cannot load such file -- #{path}" + end + + filenames = [] + if File.extname(path).size == 0 + filenames << "#{path}.rb" + filenames << "#{path}.mrb" + else + filenames << path + end + + dir = nil + filename = nil + if ['/', '.'].include? path[0] + path0 = filenames.find do |fname| + File.file?(fname) && File.exist?(fname) + end + else + dir = ($LOAD_PATH || []).find do |dir0| + filename = filenames.find do |fname| + path0 = File.join dir0, fname + File.file?(path0) && File.exist?(path0) + end + end + path0 = dir && filename ? File.join(dir, filename) : nil + end + + if path0 && File.exist?(path0) && File.file?(path0) + __require__ path0 + else + raise LoadError.new "cannot load such file -- #{path}" + end + end + + def __require__(realpath) + raise LoadError.new "File not found -- #{realpath}" unless File.exist? realpath + $" ||= [] + $__mruby_loading_files__ ||= [] + + # already required + return false if ($" + $__mruby_loading_files__).include?(realpath) + + $__mruby_loading_files__ << realpath + load realpath + $" << realpath + $__mruby_loading_files__.delete realpath + + true + end +end + + +$LOAD_PATH ||= [] +$LOAD_PATH << '.' + +if Object.const_defined?(:ENV) + $LOAD_PATH.unshift(*ENV['MRBLIB'].split(':')) unless ENV['MRBLIB'].nil? +end + +$LOAD_PATH.uniq! + +$" ||= [] +$__mruby_loading_files__ ||= [] diff --git a/web/server/h2o/libh2o/deps/mruby-require/run_test.rb b/web/server/h2o/libh2o/deps/mruby-require/run_test.rb new file mode 100644 index 000000000..2a99a9ddf --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/run_test.rb @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + + build_args = ARGV + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem :core => 'mruby-eval' + conf.gem :git => 'https://github.com/iij/mruby-io.git' + conf.gem :git => 'https://github.com/iij/mruby-dir.git' + conf.gem :git => 'https://github.com/iij/mruby-tempfile.git' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-require/src/require.c b/web/server/h2o/libh2o/deps/mruby-require/src/require.c new file mode 100644 index 000000000..0f48c0378 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/src/require.c @@ -0,0 +1,208 @@ +#if !(defined(_WIN32) || defined(_WIN64)) +#include <err.h> +#endif +#include <fcntl.h> +#include <setjmp.h> +#include <unistd.h> + +#include "mruby.h" +#include "mruby/compile.h" +#include "mruby/dump.h" +#include "mruby/string.h" +#include "mruby/proc.h" + +#include "opcode.h" +#include "error.h" + +#include <stdlib.h> +#include <sys/stat.h> + +#define E_LOAD_ERROR (mrb_class_get(mrb, "LoadError")) + +#if MRUBY_RELEASE_NO < 10000 +mrb_value mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c); +#define mrb_yield_with_class mrb_yield_internal +#endif + +#if defined(_WIN32) || defined(_WIN64) + #include <windows.h> + int mkstemp(char *template) + { + DWORD pathSize; + char pathBuffer[1000]; + char tempFilename[MAX_PATH]; + UINT uniqueNum; + pathSize = GetTempPath(1000, pathBuffer); + if (pathSize < 1000) { pathBuffer[pathSize] = 0; } + else { pathBuffer[0] = 0; } + uniqueNum = GetTempFileName(pathBuffer, template, 0, tempFilename); + if (uniqueNum == 0) return -1; + strncpy(template, tempFilename, MAX_PATH); + return open(tempFilename, _O_RDWR|_O_BINARY); + } +#endif + +static void +replace_stop_with_return(mrb_state *mrb, mrb_irep *irep) +{ + if (irep->iseq[irep->ilen - 1] == MKOP_A(OP_STOP, 0)) { + irep->iseq = mrb_realloc(mrb, irep->iseq, (irep->ilen + 1) * sizeof(mrb_code)); + irep->iseq[irep->ilen - 1] = MKOP_A(OP_LOADNIL, 0); + irep->iseq[irep->ilen] = MKOP_AB(OP_RETURN, 0, OP_R_NORMAL); + irep->ilen++; + } +} + +static int +compile_rb2mrb(mrb_state *mrb0, const char *code, int code_len, const char *path, FILE* tmpfp) +{ + mrb_state *mrb = mrb_open(); + mrb_value result; + mrbc_context *c; + int ret = -1; + int debuginfo = 1; + mrb_irep *irep; + + c = mrbc_context_new(mrb); + c->no_exec = 1; + if (path != NULL) { + mrbc_filename(mrb, c, path); + } + + result = mrb_load_nstring_cxt(mrb, code, code_len, c); + if (mrb_undef_p(result)) { + mrbc_context_free(mrb, c); + mrb_close(mrb); + return MRB_DUMP_GENERAL_FAILURE; + } + + irep = mrb_proc_ptr(result)->body.irep; + ret = mrb_dump_irep_binary(mrb, irep, debuginfo, tmpfp); + + mrbc_context_free(mrb, c); + mrb_close(mrb); + + return ret; +} + +static void +eval_load_irep(mrb_state *mrb, mrb_irep *irep) +{ + int ai; + struct RProc *proc; + + replace_stop_with_return(mrb, irep); + proc = mrb_proc_new(mrb, irep); + proc->target_class = mrb->object_class; + + ai = mrb_gc_arena_save(mrb); + mrb_yield_with_class(mrb, mrb_obj_value(proc), 0, NULL, mrb_top_self(mrb), mrb->object_class); + mrb_gc_arena_restore(mrb, ai); +} + +static mrb_value +mrb_require_load_rb_str(mrb_state *mrb, mrb_value self) +{ + char *path_ptr = NULL; +#if defined(_WIN32) || defined(_WIN64) + char tmpname[MAX_PATH] = "tmp.XXXXXXXX"; +#else + char tmpname[] = "tmp.XXXXXXXX"; +#endif + mode_t mask; + FILE *tmpfp = NULL; + int fd = -1, ret; + mrb_irep *irep; + mrb_value code, path = mrb_nil_value(); + + mrb_get_args(mrb, "S|S", &code, &path); + if (!mrb_string_p(path)) { + path = mrb_str_new_cstr(mrb, "-"); + } + path_ptr = mrb_str_to_cstr(mrb, path); + + mask = umask(077); + fd = mkstemp(tmpname); + if (fd == -1) { + mrb_sys_fail(mrb, "can't create mkstemp() at mrb_require_load_rb_str"); + } + umask(mask); + + tmpfp = fdopen(fd, "r+"); + if (tmpfp == NULL) { + close(fd); + mrb_sys_fail(mrb, "can't open temporay file at mrb_require_load_rb_str"); + } + + ret = compile_rb2mrb(mrb, RSTRING_PTR(code), RSTRING_LEN(code), path_ptr, tmpfp); + if (ret != MRB_DUMP_OK) { + fclose(tmpfp); + remove(tmpname); + mrb_raisef(mrb, E_LOAD_ERROR, "can't load file -- %S", path); + return mrb_nil_value(); + } + + rewind(tmpfp); + irep = mrb_read_irep_file(mrb, tmpfp); + fclose(tmpfp); + remove(tmpname); + + if (irep) { + eval_load_irep(mrb, irep); + } else if (mrb->exc) { + // fail to load + longjmp(*(jmp_buf*)mrb->jmp, 1); + } else { + mrb_raisef(mrb, E_LOAD_ERROR, "can't load file -- %S", path); + return mrb_nil_value(); + } + + return mrb_true_value(); +} + +static mrb_value +mrb_require_load_mrb_file(mrb_state *mrb, mrb_value self) +{ + char *path_ptr = NULL; + FILE *fp = NULL; + mrb_irep *irep; + mrb_value path; + + mrb_get_args(mrb, "S", &path); + path_ptr = mrb_str_to_cstr(mrb, path); + + fp = fopen(path_ptr, "rb"); + if (fp == NULL) { + mrb_raisef(mrb, E_LOAD_ERROR, "can't open file -- %S", path); + } + + irep = mrb_read_irep_file(mrb, fp); + fclose(fp); + + if (irep) { + eval_load_irep(mrb, irep); + } else if (mrb->exc) { + // fail to load + longjmp(*(jmp_buf*)mrb->jmp, 1); + } else { + mrb_raisef(mrb, E_LOAD_ERROR, "can't load file -- %S", path); + return mrb_nil_value(); + } + + return mrb_true_value(); +} + +void +mrb_mruby_require_gem_init(mrb_state *mrb) +{ + struct RClass *krn; + krn = mrb->kernel_module; + + mrb_define_method(mrb, krn, "_load_rb_str", mrb_require_load_rb_str, MRB_ARGS_ANY()); + mrb_define_method(mrb, krn, "_load_mrb_file", mrb_require_load_mrb_file, MRB_ARGS_REQ(1)); +} + +void +mrb_mruby_require_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/d/required.rb b/web/server/h2o/libh2o/deps/mruby-require/test/d/required.rb new file mode 100644 index 000000000..d6218cd03 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/d/required.rb @@ -0,0 +1,19 @@ +# global variables +$gvar0 = 1 +$gvar1 = 1 + +# toplevel local variables +lvar0 = 1 +lvar1 = 1 + +# define a procedure +def proc0 + :proc0 +end + +# define a new method of an existing class. +class MrubyRequireClass + def foo + :foo + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/require.rb b/web/server/h2o/libh2o/deps/mruby-require/test/require.rb new file mode 100644 index 000000000..95e1ef022 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/require.rb @@ -0,0 +1,28 @@ +assert("Kernel.require") do + # see d/required.rb + $gvar1 = 0 + lvar1 = 0 + class MrubyRequireClass; end + + assert_true require(File.join(File.dirname(__FILE__), "d", "required.rb")) + + # Kernel.require can create a global variable + assert_equal 1, $gvar0 + + # Kernel.require can change value of a global variable + assert_equal 1, $gvar1 + + # Kernel.require cannot create a local variable + assert_raise(NoMethodError) do + lvar0 + end + + # Kernel.require cannot change value of a local variable + assert_equal 0, lvar1 + + # Kernel.require can define a toplevel procedure + assert_equal :proc0, proc0 + + # Kernel.require can add a method to an existing class + assert_equal :foo, MrubyRequireClass.new.foo +end diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/test.rb b/web/server/h2o/libh2o/deps/mruby-require/test/test.rb new file mode 100644 index 000000000..0886cabef --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/test.rb @@ -0,0 +1,34 @@ +$" = [] # init + +assert "Kernel#_load_rb_str" do + assert_equal true, self.methods.include?(:_load_rb_str) + assert_equal false, Object.const_defined?(:LOAD_RB_STR_TEST) + _load_rb_str("LOAD_RB_STR_TEST = 1") + assert_equal true, Object.const_defined?(:LOAD_RB_STR_TEST) +end + +assert "$LOAD_PATH check" do + assert_equal Array, $LOAD_PATH.class +end + +assert '$" check' do + assert_equal [], $" +end + +assert('load - error check') do + assert_raise TypeError, "load(nil) should raise TypeError" do + load nil + end + assert_raise LoadError, "load('notfound') should raise LoadError" do + load 'notfound' + end +end + +assert('require - error check') do + assert_raise TypeError, "require(nil) should raise TypeError" do + require nil + end + assert_raise LoadError, "require('notfound') should raise LoadError" do + require "notfound" + end +end diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/test2.rb b/web/server/h2o/libh2o/deps/mruby-require/test/test2.rb new file mode 100644 index 000000000..b66b9fdf3 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/test2.rb @@ -0,0 +1,139 @@ +$dir = File.join(Dir.tmpdir, "mruby-require-test-#{Time.now.to_i}.#{Time.now.usec}") + +def test_setup + Dir.mkdir($dir) unless File.exist?($dir) + + File.open(File.join($dir, "test.rb"), "w") do |fp| + fp.puts "$require_test_variable = 123" + end + + File.open(File.join($dir, "test_dir.rb"), "w") do |fp| + fp.puts "$test_dir = 'test_dir'" + end + Dir.mkdir(File.join($dir, "test_dir")) + File.open(File.join($dir, "test_dir", "test_dir.rb"), "w") do |fp| + fp.puts "$test_dir2 = 'test_dir/test_dir'" + end + + File.open(File.join($dir, "test_conf.conf"), "w") do |fp| + fp.puts "$test_conf = 'test_conf'" + end + + File.open(File.join($dir, "empty.rb"), "w") + + test_reset +end + +def test_reset + $require_test_variable = nil + $test_dir = nil + $test_dir2 = nil + $test_conf = nil + $LOAD_PATH = [$dir] + $" = [] +end + +def remove_file_recursive(path) + if File.directory? path + Dir.entries(path).each do |entry| + next if ['.', '..'].include?(entry) + remove_file_recursive File.join(path, entry) + end + Dir.unlink path + else + File.unlink path + end +end + +def test_cleanup + if $dir && File.exist?($dir) + remove_file_recursive $dir + end +end + +##### +test_setup +##### + +assert("require 'test' should be success") do + test_reset + + assert_true require("test"), "require returns true when success" + assert_equal [File.join($dir, "test.rb")], $" + assert_equal 123, $require_test_variable + $require_test_variable = 789 + assert_false require("test"), "2nd require should returns false" + assert_equal 789, $require_test_variable + + test_reset + + assert_true require("test.rb"), "require should be success with '.rb'" + assert_equal [File.join($dir, "test.rb")], $" +end + +assert("require with absolute path should be success") do + test_reset + assert_true require(File.join($dir, "test")) + assert_equal [File.join($dir, "test.rb")], $" + + test_reset + assert_true require(File.join($dir, "test.rb")) + assert_equal [File.join($dir, "test.rb")], $" +end + +assert("require with absolute path && empty load_path") do + test_reset + $LOAD_PATH = [] + + assert_raise LoadError, "cannot load test.rb" do + require "test" + end + assert_equal true, require(File.join($dir, "test")) +end + +assert("require 'test_dir' should be success") do + test_reset + + assert_true require("test_dir"), "require 'test_dir' should be load 'test_dir.rb'" + assert_equal [File.join($dir, "test_dir.rb")], $" + assert_true require("test_dir/test_dir"), "require 'test_dir/test_dir' should be success" + assert_equal 'test_dir/test_dir', $test_dir2 +end + +assert("require 'test_conf' should be fail") do + test_reset + + assert_raise LoadError, "require 'test_conf.conf' should be fail" do + require("test_conf.conf") + end + assert_raise LoadError, "require method can't load *.conf" do + require File.join($dir, "test_conf.conf") + end +end + +assert("require 'empty' should be success") do + test_reset + + assert_true require("empty") + assert_equal 0, File.size(File.join($dir, "empty.rb")) +end + +assert("load 'test.rb' should be success") do + test_reset + + assert_true load(File.join($dir, "test.rb")) + assert_equal 123, $require_test_variable + assert_true $".empty? +end + +assert("load 'test_conf.conf' should be success") do + test_reset + + assert_equal true, load(File.join($dir, "test_conf.conf")) + assert_equal "test_conf", $test_conf +end + + +##### +test_cleanup +##### diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/test_context.rb b/web/server/h2o/libh2o/deps/mruby-require/test/test_context.rb new file mode 100644 index 000000000..001174748 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/test_context.rb @@ -0,0 +1,33 @@ +$dir = File.join(Dir.tmpdir, "mruby-require-test-#{Time.now.to_i}.#{Time.now.usec}") + +def test_setup + Dir.mkdir($dir) unless File.exist?($dir) + + File.open(File.join($dir, "foo.rb"), "w") do |f| + f.puts "$require_context = self" + end +end + +def test_cleanup + if $dir && File.exist?($dir) + Dir.entries($dir).each do |e| + next if ['.', '..'].include? e + File.unlink File.join($dir,e) + end + Dir.unlink $dir + end +end + + +##### +test_setup +##### + +assert("require context") do + require File.join($dir, 'foo.rb') + assert_equal self, $require_context +end + +##### +test_cleanup +##### diff --git a/web/server/h2o/libh2o/deps/mruby-require/test/test_nest_loop.rb b/web/server/h2o/libh2o/deps/mruby-require/test/test_nest_loop.rb new file mode 100644 index 000000000..c5a4b18b0 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-require/test/test_nest_loop.rb @@ -0,0 +1,58 @@ +$dir = File.join(Dir.tmpdir, "mruby-require-test-#{Time.now.to_i}.#{Time.now.usec}") + +def test_setup + Dir.mkdir($dir) + + File.open(File.join($dir, "loop1.rb"), "w") do |fp| + fp.puts "require 'loop2.rb'" + fp.puts "$loop1 = 'loop1'" + end + File.open(File.join($dir, "loop2.rb"), "w") do |fp| + fp.puts "require 'loop1.rb'" + fp.puts "$loop2 = 'loop2'" + end + + $require_test_count = 10 + (1..$require_test_count-1).each do |i| + File.open(File.join($dir, "#{i+1}.rb"), "w") do |fp| + fp.puts "require '#{i}'" + fp.puts "s = 0" + (0..100).each{|num| fp.puts "s += #{num}" } + end + end + File.open(File.join($dir, "1.rb"), "w") do |fp| + fp.puts "$require_test_0 = 123" + end + + $LOAD_PATH = [$dir] +end + +def test_cleanup + if $dir && File.exist?($dir) + Dir.entries($dir).each do |e| + next if ['.', '..'].include? e + File.unlink File.join($dir,e) + end + Dir.unlink $dir + end +end + +##### +test_setup +##### + +assert("require loop check") do + require 'loop1' + assert_equal 'loop1', $loop1 + assert_equal 'loop2', $loop2 +end + +assert("require nest") do + before = $".size + require "#{$require_test_count}" + assert_equal before + $require_test_count, $".size +end + +##### +test_cleanup +##### |