mruby 元编程能力全解:mruby-metaprog 的反射与动态方法操作指南

发布时间:2026/10/12 3:34:58

mruby 元编程能力全解:mruby-metaprog 的反射与动态方法操作指南 编程语言语言运行时编译器解释器嵌入式【免费下载链接】mrubyLightweight Ruby项目地址https://gitcode.com/gh_mirrors/mr/mruby点击查看免费下载mruby-metaprog 是 mruby 官方仓库中提供元编程metaprogramming能力的 mrbgem它以Kernel与Module两个核心类为载体将运行时检查自身结构、动态读写变量、按需定义与移除方法等能力带进嵌入式 Ruby 环境。本文围绕 mruby-metaprog/README.md 展开结合 metaprog.c 的源码实现与 metaprog.rb 的测试用例逐一讲解实例变量/类变量操作、方法清单查询、单例方法定义、方法移除、常量与模块嵌套检查等全部 API读完即可在 mruby 中完成对象内省与动态行为注入。mruby-metaprog 是什么mruby 本身是面向嵌入式环境的轻量级 Ruby 实现其默认 gem 集合中并不包含全套反射 API。mruby-metaprog这个 mrbgem 的作用就是把元编程常用的方法以 C 扩展的形式补齐并在运行时通过mrb_mruby_metaprog_gem_init见 metaprog.c挂载到Kernel模块和Module类上挂在Kernel上作用于所有对象的有instance_variable_*、methods、singleton_methods、define_singleton_method、send、public_send、global_variables、local_variables等挂在Module上作用于类与模块的有class_variable_*、instance_methods、remove_method、constants、included_modules、Module.nesting等。其 mrbgem 描述文件 mrbgem.rake 声明了 MIT 许可与 Meta-programming features for mruby 的定位且被核心 gem 盒 metaprog.gembox 收录同时配合mruby-method、mruby-eval、mruby-binding等 gem 使用默认配置 build_config 中的 default.gembox 也直接启用了它因此常规构建即可使用。安装与启用方式mruby 通过build_config.rb中的 gem 盒gembox机制管理 mrbgem。要启用元编程能力只需保证构建配置中包含mruby-metaprogMRuby::Build.new do |conf| conf.gembox default # 默认 gembox 已包含 mruby-metaprog # 或显式指定 # conf.gem :core mruby-metaprog end也可以单独使用精简 gem 盒 metaprog.gembox它除mruby-metaprog外还串联了mruby-methodMethod/UnboundMethod 类、mruby-eval、mruby-binding、mruby-proc-binding与mruby-compiler构成一套完整的运行时反射与求值环境。构建完成后用mruby二进制运行脚本即可调用下述所有 API。实例变量操作在运行时读写对象的内部状态Kernel上提供的四个实例变量方法分别对应元编程中最常见的检查、读取、写入、列举四个动作其实现位于 metaprog.c每个方法在调用底层存取函数前都会执行mrb_iv_name_sym_check做名称合法性校验——该函数定义于 variable.c对非法实例变量名直接抛出NameError。方法签名行为instance_variable_defined?(symbol)返回true/false判断实例变量是否已定义instance_variable_get(symbol)读取实例变量值未设置时返回nil名称非法抛NameErrorinstance_variable_set(symbol, value)写入实例变量并返回该值变量无需预先存在instance_variables()返回实例变量名Symbol数组典型的完整用法如下摘自原 README 示例class MyClass def initialize(value) my_var value end end obj MyClass.new(10) p obj.instance_variable_defined?(:my_var) # true p obj.instance_variable_get(:my_var) # 10 obj.instance_variable_set(:another_var, hello) p obj.instance_variables # [:my_var, :another_var]从源码层面看instance_variable_get/set最终委托给mrb_iv_get/mrb_iv_set而instance_variables的列表枚举在 variable.c 实现对采用 shape 优化MRB_OBJ_SHAPED_P的对象走shaped_iv_foreach否则遍历普通iv哈希表这正是 mruby 4.x 引入对象 shape 机制后实例变量存储布局的体现。测试用例 metaprog.rb 进一步验证了这些边界行为名称参数可以是 Symbol 或 String字符串会被自动转换为 Symbol非法名称如0、foo、1等会触发NameError冻结对象freeze后再instance_variable_set会抛FrozenErrornil等特殊对象调用写方法会抛FrozenError或ArgumentError。方法清单查询methods 系列与可见性语义mruby-metaprog 在Kernel上提供五个方法查询 API用于枚举对象可访问的方法名。它们在 C 层的入口统一为mrb_obj_methods见 metaprog.c通过mrb_get_args(mrb, |b, regular)解析可选布尔参数再以不同的可见性标志调用mrb_class_instance_method_list方法默认参数可见性筛选methods(regulartrue)true含祖先链public protectedpublic_methods(alltrue)truepublicprotected_methods(alltrue)trueprotectedprivate_methods(alltrue)trueprivatesingleton_methods(alltrue)truepublic protected单例方法mrb_class_instance_method_list见 metaprog.c是方法清单查询的底层引擎它用khash哈希集合做去重recurfalse时只扫描当前类的方法表遇到 prepend 时经MRB_CLASS_ORIGIN定位真实类recurtrue时沿super链向上逐层收集最终把mrb_mt_foreach收集到的 Symbol 放入数组返回。原 README 的示例展示了参数false的含义——只列出接收者自身定义的方法class AnotherClass def public_method; end protected def protected_method; end private def private_method; end end obj AnotherClass.new p obj.public_methods(false) # [:public_method] p obj.protected_methods(false) # [:protected_method] p obj.private_methods(false) # [:private_method] def obj.singleton_method_example; end p obj.singleton_methods # [:singleton_method_example]配套测试metaprog.rb验证了返回类型为Array且methods(false)只包含类自身的方法如Class.new{def self.foo; end}.methods(false)为[:foo]。singleton_methods的实现在 metaprog.c先检查对象所属类是否为单例类MRB_TT_SCLASSrecurtrue时还会继续沿单例类与 ICLASSinclude 生成的中间类向上收集被引入模块中的方法。定义单例方法define_singleton_method 的动态注入define_singleton_method(name, block)允许为任意对象动态注入只属于该对象的方法这是元编程中运行时扩展单个实例的典型手段。其 C 实现mod_define_singleton_method见 metaprog.c先取得对象的单例类再复用mrb_mod_define_method_m定义于 class.c因此定义出的方法会自动继承当前作用域的可见性caller_scope_visibility并与Module#define_method走同一条底层define_method_m管线。原 README 示例obj Object.new obj.define_singleton_method(:greet) do |name| Hello, #{name}! end p obj.greet(World) # Hello, World!测试metaprog.rb确认了该方法的返回值是新方法名 Symbolassert_equal :test_method, ret同时验证了两类拒绝场景数字等不可单例化的对象抛TypeError冻结对象抛FrozenError。README 中提到的配套能力singleton_class也在本 gem 中一并注册测试metaprog.rb验证了obj.singleton_class与class obj; self end是同一对象且冻结对象后其单例类也随之冻结。类变量操作Module 上的读写与移除类变量var作用于类/模块及其继承链mruby-metaprog 在Module上提供五个相关方法。C 层实现见 metaprog.c在每次操作前都会调用check_cv_name_sym做名称校验类变量名必须以开头、第三个字符不能是数字、且整体必须是指标识符cv_name_p的判定逻辑否则抛出NameError。方法签名行为class_variable_defined?(symbol)返回true/false判断类变量是否定义含继承链class_variable_get(symbol)读取类变量值未定义时抛NameErrorclass_variable_set(symbol, value)写入类变量并返回该值class_variables(inherittrue)可选布尔参数返回类变量名 Symbol 数组默认沿super链收集remove_class_variable(symbol)移除类变量并返回其值不可移除继承变量原 README 的完整示例class ParentClass parent_cvar 100 end class ChildClass ParentClass child_cvar 200 def self.get_parent_cvar class_variable_get(:parent_cvar) end end p ChildClass.class_variable_defined?(:child_cvar) # true p ChildClass.class_variable_get(:child_cvar) # 200 ChildClass.class_variable_set(:new_cvar, 300) p ChildClass.class_variables.sort # [:child_cvar, :new_cvar, :parent_cvar] (order may vary) p ChildClass.get_parent_cvar # 100 ChildClass.remove_class_variable(:new_cvar) p ChildClass.class_variables.sort # [:child_cvar, :parent_cvar] (order may vary)class_variables的底层实现在 variable.cinherit默认为true沿super链逐层用cv_i回调过滤出以开头的变量名remove_class_variable的实现在 metaprog.c它先尝试直接移除若变量实际定义在祖先类中则抛出NameErrorcannot remove … for …。类变量与常量一样存放在类的实例变量表中mrb_cv_get/mrb_cv_set会沿继承链查找见 variable.c。测试用例metaprog.rb覆盖了更多细节include/prepend模块中设置的类变量对宿主类可见非法名称如2、a?、x、x全部抛NameError冻结的模块或冻结父类下再class_variable_set抛FrozenError。模块与类的方法内省instance_methods 系列针对类/模块本身mruby-metaprog 提供了按可见性分类的实例方法清单查询全部经由mod_instance_methods见 metaprog.c再转发到前文提到的mrb_class_instance_method_list方法默认参数含义instance_methods(include_supertrue)truepublic protected 实例方法public_instance_methods(include_supertrue)truepublic 实例方法private_instance_methods(include_supertrue)trueprivate 实例方法protected_instance_methods(include_supertrue)trueprotected 实例方法undefined_instance_methods()无参数被undef掉的实例方法名原 README 中instance_methods(include_supertrue)的语义是参数为false时只列出当前模块/类自身的方法为true时连同父类superclass中的方法一起返回。测试metaprog.rb给出了典型断言B.instance_methods(false)只含[:method2]而C.instance_methods(true)同时包含继承来的:method2与自己定义的:method3。值得注意的两个细节prepend 兼容测试metaprog.rb专门验证了prepend Module.new之后instance_methods(false)仍然只报告真实类自身定义的方法未实现方法与 undefined 方法undefined_instance_methods通过undefined_method_i回调见 metaprog.c扫描方法表中MRB_METHOD_UNDEF_P标记的条目。测试metaprog.rb还演示了方法已定义但未实现not implemented的情况instance_methods(false)会列出:gone但respond_to?(:gone)返回false。此外Module上还注册了三个可见性判定方法public_method_defined?、private_method_defined?、protected_method_defined?均支持(symbol, inherittrue)双参数其共同后端是mrb_mod_method_visibility见 class.c——inheritfalse时从类的 origin 开始查找确保只统计类自身拥有的方法测试metaprog.rb对 include 继承、子类可见性改变、undef_method后判定、非 Symbol/String 参数抛TypeError、多余参数抛ArgumentError等场景均有断言。移除方法remove_method 与 mruby 的特殊处理Module#remove_method(symbol)从当前类/模块中移除指定方法返回selfC 层见 metaprog.c。mruby 实现支持一次传入多个参数mrb_get_args(mrb, *, ...)并在每次移除后做 GC arena 恢复以避免内存膨胀调用前会通过mrb_check_frozen检查对象是否冻结。与 CRuby 相同remove_method只移除当前类自己的定义若方法实际定义在父类或 include 的模块中则会抛NameError。测试metaprog.rb验证了这一点——从Child移除:hello后instance_methods.include?(:hello)仍为true来自父类而instance_methods(false)不再包含它。其余边界测试包括参数不是 Symbol/String 时抛TypeErrormetaprog.rb移除方法会触发method_removed回调本 gem 以mrb_f_nil占位注册该回调见 metaprog.c测试验证了回调收到被移除的方法名metaprog.rb冻结类上调用抛FrozenError一个有趣的场景对Integerprepend 模块后移除其中的-方法能让内建运算符解析回原生的 builtin 实现metaprog.rb。常量检查与模块嵌套constants 与 Module.nestingModule#constants(inherittrue)返回模块/类中定义的常量名数组inherit默认为true会沿继承链含Object之上的终止判断收集。C 层实现mrb_mod_constants在 variable.c逐层调用mrb_mod_const_at遍历类的常量表。测试metaprog.rb验证了 include/prepend 的模块常量对宿主类可见。Module.nesting()返回当前词法作用域lexical scope的模块嵌套数组这是 mruby-metaprog 中实现最贴近运行时的方法其 C 实现mrb_mod_s_nesting见 metaprog.c从当前调用帧mrb-c-ci[-1].proc出发沿proc-upper闭包链回溯只收集带词法作用域MRB_PROC_SCOPE_P且非被给予的MRB_PROC_GIVEN_Pproc 的目标类去重后压入数组。README 未给出示例但测试metaprog.rb演示了标准行为module Test4ModuleNesting module Test4ModuleNesting2 Module.nesting # [Test4ModuleNesting2, Test4ModuleNesting] end endModule.constants在Object等接收者上还有特殊行为mrb_mod_s_constants见 metaprog.c在调用者是Module类本身Module.constants形式时会沿调用者词法作用域链收集常量而不是简单返回Module自身测试metaprog.rb验证了Module.constants看到的是词法作用域Test4GivenNestingLex的常量而非接收类的常量。消息发送与变量清单send、public_send、global_variables、local_variablessend 与 public_sendsend(symbol, *args, block)与public_send(symbol, *args, block)都在Kernel上注册见 metaprog.c其 C 实现位于 vm.c二者唯一的差别是传给send_method的pub标志send忽略可见性可调用 private/protected 方法public_send只调用 public 方法调用 private/protected 方法时抛NoMethodError。两者都支持字符串转 Symbol、位置参数与块参数。测试metaprog.rb覆盖了带块调用send(:lambda)、带参数调用以及无参无块调用可见性测试metaprog.rb确认send(:priv)/send(:prot)成功而public_send(:priv)抛NoMethodError且public_send对未定义方法会回退到method_missing。另外mruby 核心的__send__与本 gem 的send底层同源mrb_f_send同时注册为__send__见 class.c名称冲突时可用__send__规避。global_variables 与 local_variablesglobal_variables返回当前所有全局变量名以$开头的数组C 实现在 variable.c直接遍历 mruby 状态中的全局变量表mrb-globals。测试metaprog.rb验证了新建一个$kernel_global_variables_test nil后清单恰好增加一项。注意在Kernel上注册的是实例方法Kernel#global_variables而Kernel.global_variables类方法形式并未提供测试第 113 行有明确注释。local_variables返回当前作用域局部变量名数组C 实现metaprog.c通过mrb_proc_local_variables从当前调用帧mrb-c-ci[-1].proc中解析。原 README 与源码注释都标注了一个mruby 特有的限制如果编译产物经过mruby-strip -l剥离了局部变量符号信息此方法将始终返回空数组metaprog.c。测试metaprog.rb同时验证了闭包语义define_method创建的块会保留其定义时闭包的局部变量因此local_variables能看到块外层的b、kl等变量。组合应用一个完整的元编程实战示例把上述 API 组合起来可以写出典型的动态扩展 内省程序# 为对象动态注入方法 class Greeter def initialize(name) name name define_singleton_method(:greet) { Hi, #{name}! } end end g Greeter.new(mruby) p g.greet # Hi, mruby! p g.singleton_methods # [:greet] p g.instance_variable_get(:name) # mruby # 内省类结构 module M; def m1; end; end class Base include M C 1 cv 2 def b1; end end p Base.included_modules # [M] p Base.instance_methods(false) # [:b1] p Base.constants # [:C] p Base.class_variables # [:cv] # 动态发送 p g.send(:greet) # Hi, mruby! # 移除方法 class Base remove_method :b1 end p Base.instance_methods(false) # []小结mruby-metaprog 以约 800 行 C 代码metaprog.c为 mruby 补全了覆盖变量读写、方法清单、单例方法、类变量、模块内省、方法移除、常量/嵌套、消息发送八类场景的元编程 API并大量复用 mruby 核心的variable.c、class.c、vm.c基础设施保证与主实现共享同一套可见性、冻结与 GC 语义。对于需要在嵌入式环境中实现插件化架构、调试探针、动态代理或序列化框架的开发者README 提供了全部 API 的速查索引测试用例 则是理解边界行为NameError、FrozenError、inherit 参数语义的最佳参考。使用时请留意两个 mruby 特有差异local_variables在剥离符号信息的二进制中恒为空数组以及Kernel.global_variables类方法形式未提供。赞分享编程语言语言运行时编译器解释器嵌入式【免费下载链接】mrubyLightweight Ruby项目地址https://gitcode.com/gh_mirrors/mr/mruby点击查看免费下载相关推荐mruby 的 Module/Class 反射扩展mruby-class-ext 完整指南mruby 的 Module/Class 反射扩展mruby class ext 完整指南 导读 mruby class ext 是 mruby 官方仓库中提编程语言语言运行时编译器解释器嵌入式mruby-method 深度解析为 mruby 实现 Method 与 UnboundMethod 反射机制mruby method 深度解析为 mruby 实现 Method 与 UnboundMethod 反射机制 mruby method 是 mruby 生态可观测性日志分析云原生流处理H2O 内置 mruby 的 Method / UnboundMethod 反射机制mruby-method 详解与源码剖析H2O 内置 mruby 的 Method / UnboundMethod 反射机制mruby method 详解与源码剖析 导读 mruby method后端网络上一篇PPTTimer如何用智能自动化计时器提升演示效率的终极指南下一篇AMD Ryzen处理器调优终极指南5分钟掌握SDT调试工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/12 3:34:58

web服务常见漏洞(nginx)

文章目录漏洞背景与解决过程1. 目标使用过期的 TLS 1.0 版协议2. 目标主机支持 RSA 密钥交换3. 可通过 HTTP(S) 获取远端 WWW 服务信息4. 探测到服务器支持的 SSL 加密协议5. 目标 X-Content-Type-Options 响应头缺失6. 目标 Content-Security-Policy 响应头缺失7. 目标 X-Down…

2026/10/12 3:24:34

现代公寓内景全解:动线比例、材质灯光与渲染落地实战指南

现代公寓内部场景这个题目,这几年被问到的频率特别高。圈内人看到“现代公寓内景”这个词,第一反应往往不是某个具体风格,而是一整套关于比例、材质、光线和秩序的处理方式。这篇就从一个刚完成的内景项目说起,把这几年折腾现代公…

2026/10/12 5:55:05

Java+Vue房产租赁管理系统:从业务建模到前后端部署全解析

做这个东西之前,我其实已经看过不少毕业设计和课设选题,十个人里至少有六七个会选管理系统类。但真正上手去写一个发布出来、能跑通、能提交的完整项目时,很多人卡壳的点根本不是"不会写代码",而是不知道一个像样的系统…

2026/10/12 5:55:05

SLF4J与Spring Boot日志实战:绑定、桥接、MDC与配置全解析

1. 既然Spring Boot已经把日志接到底层了,为什么还要单独聊SLF4J先说一个我真实遇到的场景。去年排查一个线上问题,业务反馈某个订单状态更新没有记录到任何日志,但同类的其他订单都有。我打开代码一看,发现团队里有人直接在Servi…

2026/10/12 5:55:05

跨站请求伪造(CSRF)攻防全解析:从浏览器特性到纵深防御

1. CSRF 困局的本质&#xff1a;浏览器的“代理人困境”1.1 Cookie 自动提交&#xff1a;一段关乎历史的“信任设计”先说个真实场景。某天你登录了某家银行的网银系统&#xff0c;顺手开了个新标签页刷论坛。论坛帖子底部嵌了个不起眼的<img>标签&#xff0c;指向银行转…

2026/10/12 5:55:05

Oracle Client 11g安装实战:从tnsnames.ora配置到SQL*Plus连接验证

简介&#xff1a;Oracle客户端11g安装包是面向数据库开发、运维人员及初学者的完整客户端组件&#xff0c;用于连接Oracle服务器、执行SQL查询和日常管理。压缩包共710个文件、约270.95MB&#xff0c;以jar、xml、properties配置与运行库为主&#xff0c;并含dll、nls、exe等语…

2026/10/12 5:55:05

C++跨平台移植设计:从环境依赖到工程化隔离方案

从“换个环境就跑不起来”到真正可移植的工程&#xff0c;中间隔着的不是运气&#xff0c;而是你有没有认真做过移植性设计。C这门语言看起来到处都是标准&#xff0c;实际写起来处处是坑&#xff1a;同一段代码在 Windows 上编译通过&#xff0c;到了 Linux 直接报错&#xff…

2026/10/12 5:50:05

微信小程序上线全流程:纯前端开发者必知的避坑指南

做微信小程序开发这两年&#xff0c;我最大的感受是&#xff1a;写代码不是最难的部分&#xff0c;真正折磨人的是那个“写完了却上不了线”的阶段。尤其是纯前端背景的开发者&#xff0c;习惯了自己打包、自己部署、自己说了算的那套工作流&#xff0c;一碰到小程序平台&#…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”&#xff0c;而是它给出一段看起来合理的说明&#xff0c;程序却从中猜错优先级。通俗做法是&#xff1a;要求模型只交 JSON&#xff08;JavaScript Object Notation&#xff0c;轻量数据格式&#xff09;&#xff0c;再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里&#xff0c;有A同学跑来问我&#xff1a;选什么毕设题目最稳妥&#xff0c;既能让评审老师觉得工作量够&#xff0c;又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友&#xff0c;在看完一堆“Hello World”和基础组件之后&#xff0c;大概率都会撞上同一堵墙&#xff1a;StatefulWidget 里那堆 initState、build、dispose 方法&#xff0c;到底什么时候被调用&#xff1f;为什么顺序是那样&#xff1f;在里面到…

2026/10/12 0:04:22

绝缘子缺陷检测数据集清洗与工业级训练实战指南

简介&#xff1a;本资源是面向电力AI研发人员、工业视觉工程师及智能巡检系统开发者的绝缘子缺陷检测专用YOLO格式数据集&#xff0c;解决无人机航拍场景下绝缘子破损、污闪、积雪等9类典型缺陷的精准识别与定位难题。数据集共2139张真实巡检图像&#xff08;含训练/验证/测试集…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑