first commit
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
MRuby::Gem::Specification.new('mruby-object-ext') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'extensional methods shared by all objects'
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
module Kernel
|
||||
# call-seq:
|
||||
# obj.yield_self {|_obj|...} -> an_object
|
||||
# obj.then {|_obj|...} -> an_object
|
||||
#
|
||||
# Yields <i>obj</i> and returns the result.
|
||||
#
|
||||
# 'my string'.yield_self {|s|s.upcase} #=> "MY STRING"
|
||||
#
|
||||
def yield_self(&block)
|
||||
return to_enum :yield_self unless block
|
||||
block.call(self)
|
||||
end
|
||||
alias then yield_self
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# obj.tap{|x|...} -> obj
|
||||
#
|
||||
# Yields <code>x</code> to the block, and then returns <code>x</code>.
|
||||
# The primary purpose of this method is to "tap into" a method chain,
|
||||
# in order to perform operations on intermediate results within the chain.
|
||||
#
|
||||
# (1..10) .tap {|x| puts "original: #{x.inspect}"}
|
||||
# .to_a .tap {|x| puts "array: #{x.inspect}"}
|
||||
# .select {|x| x%2==0} .tap {|x| puts "evens: #{x.inspect}"}
|
||||
# .map { |x| x*x } .tap {|x| puts "squares: #{x.inspect}"}
|
||||
#
|
||||
def tap
|
||||
yield self
|
||||
self
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,132 @@
|
||||
#include <mruby.h>
|
||||
#include <mruby/array.h>
|
||||
#include <mruby/class.h>
|
||||
#include <mruby/hash.h>
|
||||
#include <mruby/proc.h>
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* nil.to_a -> []
|
||||
*
|
||||
* Always returns an empty array.
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
nil_to_a(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
return mrb_ary_new(mrb);
|
||||
}
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
/*
|
||||
* call-seq:
|
||||
* nil.to_f -> 0.0
|
||||
*
|
||||
* Always returns zero.
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
nil_to_f(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
return mrb_float_value(mrb, 0.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* nil.to_h -> {}
|
||||
*
|
||||
* Always returns an empty hash.
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
nil_to_h(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
return mrb_hash_new(mrb);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* nil.to_i -> 0
|
||||
*
|
||||
* Always returns zero.
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
nil_to_i(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
return mrb_fixnum_value(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.itself -> an_object
|
||||
*
|
||||
* Returns <i>obj</i>.
|
||||
*
|
||||
* string = 'my string' #=> "my string"
|
||||
* string.itself.object_id == string.object_id #=> true
|
||||
*
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_f_itself(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.instance_exec(arg...) {|var...| block } -> obj
|
||||
*
|
||||
* Executes the given block within the context of the receiver
|
||||
* (_obj_). In order to set the context, the variable +self+ is set
|
||||
* to _obj_ while the code is executing, giving the code access to
|
||||
* _obj_'s instance variables. Arguments are passed as block parameters.
|
||||
*
|
||||
* class KlassWithSecret
|
||||
* def initialize
|
||||
* @secret = 99
|
||||
* end
|
||||
* end
|
||||
* k = KlassWithSecret.new
|
||||
* k.instance_exec(5) {|x| @secret+x } #=> 104
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
mrb_obj_instance_exec(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
const mrb_value *argv;
|
||||
mrb_int argc;
|
||||
mrb_value blk;
|
||||
struct RClass *c;
|
||||
|
||||
mrb_get_args(mrb, "*&!", &argv, &argc, &blk);
|
||||
c = mrb_singleton_class_ptr(mrb, self);
|
||||
if (mrb->c->ci->acc < 0) {
|
||||
return mrb_yield_with_class(mrb, blk, argc, argv, self, c);
|
||||
}
|
||||
mrb->c->ci->target_class = c;
|
||||
return mrb_yield_cont(mrb, blk, self, argc, argv);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_object_ext_gem_init(mrb_state* mrb)
|
||||
{
|
||||
struct RClass * n = mrb->nil_class;
|
||||
|
||||
mrb_define_method(mrb, n, "to_a", nil_to_a, MRB_ARGS_NONE());
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
mrb_define_method(mrb, n, "to_f", nil_to_f, MRB_ARGS_NONE());
|
||||
#endif
|
||||
mrb_define_method(mrb, n, "to_h", nil_to_h, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE());
|
||||
|
||||
mrb_define_method(mrb, mrb->kernel_module, "itself", mrb_f_itself, MRB_ARGS_NONE());
|
||||
|
||||
mrb_define_method(mrb, mrb_class_get(mrb, "BasicObject"), "instance_exec", mrb_obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK());
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_object_ext_gem_final(mrb_state* mrb)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
assert('NilClass#to_a') do
|
||||
assert_equal [], nil.to_a
|
||||
end
|
||||
|
||||
assert('NilClass#to_f') do
|
||||
skip unless Object.const_defined?(:Float)
|
||||
assert_equal 0.0, nil.to_f
|
||||
end
|
||||
|
||||
assert('NilClass#to_h') do
|
||||
assert_equal Hash.new, nil.to_h
|
||||
end
|
||||
|
||||
assert('NilClass#to_i') do
|
||||
assert_equal 0, nil.to_i
|
||||
end
|
||||
@@ -0,0 +1,53 @@
|
||||
assert('Object#instance_exec') do
|
||||
class KlassWithSecret
|
||||
def initialize
|
||||
@secret = 99
|
||||
end
|
||||
end
|
||||
k = KlassWithSecret.new
|
||||
assert_equal 104, k.instance_exec(5) {|x| @secret+x }
|
||||
end
|
||||
|
||||
assert('Object#tap') do
|
||||
ret = []
|
||||
(1..10) .tap {|x| ret << "original: #{x.inspect}"}
|
||||
.to_a .tap {|x| ret << "array: #{x.inspect}"}
|
||||
.select {|x| x%2==0} .tap {|x| ret << "evens: #{x.inspect}"}
|
||||
.map { |x| x*x } .tap {|x| ret << "squares: #{x.inspect}"}
|
||||
|
||||
assert_equal [
|
||||
"original: 1..10",
|
||||
"array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]",
|
||||
"evens: [2, 4, 6, 8, 10]",
|
||||
"squares: [4, 16, 36, 64, 100]"
|
||||
], ret
|
||||
assert_equal(:tap_ok, Class.new {def m; tap{return :tap_ok}; end}.new.m)
|
||||
end
|
||||
|
||||
assert('instance_exec on primitives with class and module definition') do
|
||||
begin
|
||||
class A
|
||||
1.instance_exec do
|
||||
class B
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert_kind_of Class, A::B
|
||||
ensure
|
||||
Object.remove_const :A
|
||||
end
|
||||
|
||||
begin
|
||||
class A
|
||||
1.instance_exec do
|
||||
module B
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert_kind_of Module, A::B
|
||||
ensure
|
||||
Object.remove_const :A
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user