Last active
December 6, 2018 15:16
-
-
Save hanachin/fb9bb1a5c75b76b3b337b25f502d9882 to your computer and use it in GitHub Desktop.
refineをしてるモジュール取り出せるrefinements_robbery gem ref: https://qiita.com/hanachin_/items/20c1b77936962ee07a7d
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "refinements_robbery" | |
class C | |
using Module.new { | |
refine(C) { | |
def hi | |
puts "hi" | |
end | |
} | |
} | |
end | |
# C.new.hi # NoMethodError | |
using *RefinementsRobbery.rob(C) | |
C.new.hi | |
# hi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class User | |
# Refinements で隠蔽したいメソッドを定義する | |
# また Module.new で動的にモジュールを定義することで | |
# あとから using することも防ぐ事が出来る | |
using Module.new { | |
refine User do | |
def name | |
@__name__ | |
end | |
end | |
} | |
def initialize name | |
@__name__ = name | |
end | |
def to_s | |
"name is #{name}" | |
end | |
end | |
class UserEx < User | |
def meth | |
# using してないコンテキストなので参照できない!! | |
name | |
end | |
end | |
homu = UserEx.new "homu" | |
# Error: undefined local variable or method `name' for #<UserEx:0x000055998748ee48 @__name__="homu"> (NameError) | |
p homu.meth |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ObjectSpace.each_object(Module) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
p Module.new { p refine(Object) {} } | |
# #<refinement:Object@#<Module:0x000055981dd1f7a8>> | |
# #<Module:0x000055981dd1f7a8> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% cd path/to/ruby | |
% git grep refinement: | |
doc/ChangeLog-2.0.0: a refinement, returns a string in the format #<refinement:C@M>, | |
doc/syntax/refinements.rdoc:Here is a basic refinement: | |
object.c: VALUE s = rb_usascii_str_new2("#<refinement:"); | |
test/ruby/test_refinement.rb: assert_equal("#<refinement:Integer@TestRefinement::Inspect::M>", |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
refined_class = rb_refinement_module_get_refined_class(klass); | |
if (!NIL_P(refined_class)) { | |
VALUE s = rb_usascii_str_new2("#<refinement:"); | |
rb_str_concat(s, rb_inspect(refined_class)); | |
rb_str_cat2(s, "@"); | |
CONST_ID(id_defined_at, "__defined_at__"); | |
defined_at = rb_attr_get(klass, id_defined_at); | |
rb_str_concat(s, rb_inspect(defined_at)); | |
rb_str_cat2(s, ">"); | |
return s; | |
} | |
return rb_str_dup(rb_class_name(klass)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def rb_intern_str(str) | |
rb_intern_str = Fiddle::Handle::DEFAULT["rb_intern_str"] | |
rb_intern_str_f = Fiddle::Function.new(rb_intern_str, [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP) | |
rb_intern_str_f.call(Fiddle.dlwrap(str)) | |
end | |
def rb_attr_get(mod, str) | |
id = rb_intern_str(str) | |
rb_attr_get = Fiddle::Handle::DEFAULT["rb_attr_get"] | |
rb_attr_get_f = Fiddle::Function.new(rb_attr_get, [Fiddle::TYPE_VOIDP] * 2, Fiddle::TYPE_VOIDP) | |
m = Fiddle.dlwrap(mod) | |
Fiddle.dlunwrap(rb_attr_get_f.call(m, id)) | |
end | |
def defined_at(mod) | |
rb_attr_get(mod, "__defined_at__") | |
end | |
def rb_refinement_module_get_refined_class(mod) | |
rb_attr_get(mod, "__refined_class__") | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def rob(klass) | |
ObjectSpace.each_object(Module).select {|m| | |
# 対象のクラスをrefineしているか調べる | |
rb_refinement_module_get_refined_class(m) == klass | |
}.map {|m| | |
# refineをまとめているRefinementsのモジュールをたどる | |
defined_at(m) | |
}.uniq | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class User | |
# Refinements で隠蔽したいメソッドを定義する | |
# また Module.new で動的にモジュールを定義することで | |
# あとから using することも防ぐ事が出来る | |
using Module.new { | |
refine User do | |
def name | |
@__name__ | |
end | |
end | |
} | |
def initialize name | |
@__name__ = name | |
end | |
def to_s | |
"name is #{name}" | |
end | |
end | |
class UserEx < User | |
def meth | |
# using してないコンテキストなので参照できない!! | |
name | |
end | |
end | |
homu = UserEx.new "homu" | |
# p homu.meth # undefined local variable or method `name' for #<UserEx:0x0000563939f98bc0 @__name__="homu"> (NameError) | |
require "refinements_robbery" | |
class UserEx < User | |
# UserのRefinementsをあとから using する | |
using *RefinementsRobbery.rob(User) | |
def meth2 | |
# using しているコンテキストなので参照できる!! | |
name | |
end | |
end | |
homu = UserEx.new "homu" | |
p homu.meth2 | |
# "homu" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment