- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章ruby元编程实际使用实例由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
很喜欢ruby元编程,puppet和chef用到了很多ruby的语言特性,来定义一个新的部署语言。 分享几个在实际项目中用到的场景,能力有限,如果有更优方案,请留言给我:) 。
rpc接口模板化——使用eval、alias、defind_method 。
1
2
3
4
5
6
7
8
9
|
require
'rack/rpc'
class
Server < Rack::
RPC
::Server
def
hello_world
"Hello, world!"
end
rpc
'hello_world'
=>
:hello_world
end
|
上面是一个rpc server,编写一个函数,调用rpc命令进行注册.
采用define_method、eval、alias方法,可以实现一个判断rpc/目录下的*.rb文件,进行加载和rpc接口注册的功能,实现代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
module
RPC
require
'rack/rpc'
#require rpc/*.rb文件
Dir
.glob(
File
.join(
File
.dirname(
__FILE__
),
'rpc'
,
"*.rb"
))
do
|file|
require file
end
class
Runner < Rack::
RPC
::Server
#include rpc/*.rb and regsiter rpc call
#eg. rpc/god.rb god.hello
@@rpc_list
= []
Dir
.glob(
File
.join(
File
.dirname(
__FILE__
),
'rpc'
,
"*.rb"
))
do
|file|
rpc_class =
File
.basename(file).split(
'.rb'
)[
0
].capitalize
rpc_list = []
#加载module下的方法到Runner这个类下面
eval
"include Frigga::RPC::#{rpc_class}"
#获取声明的RPC接口
eval
"rpc_list = Frigga::RPC::#{rpc_class}::RPC_LIST"
rpc_list.
each
do
|rpc_name|
#alias一个新的rpc方法,叫old_xxxx_xxxx
eval
"alias :old_#{rpc_class.downcase}_#{rpc_name} :#{rpc_name}"
#重新定义rpc方法,添加一行日志打印功能,然后再调用old_xxxx_xxxx rpc方法
define_method
"#{rpc_class.downcase}_#{rpc_name}"
.to_sym
do
|*arg|
Logger.info
"[#{request.ip}] called #{rpc_class.downcase}.#{rpc_name} #{arg.join(', ')}"
eval
"old_#{rpc_class.downcase}_#{rpc_name} *arg"
end
#注册RPC调用
rpc
"#{rpc_class.downcase}.#{rpc_name}"
=>
"#{rpc_class.downcase}_#{rpc_name}"
.to_sym
#添加到全局变量,汇总所有的rpc方法
@@rpc_list
<<
"#{rpc_class.downcase}.#{rpc_name}"
end
end
def
help
rpc_methods = ([
'help'
] +
@@rpc_list
.sort).join(
"\n"
)
end
rpc
"help"
=>
:help
end
end
#RPC
|
。
完成上述功能后,可以非常方便的开发rpc接口,例如下面这个IP地址增、删、查的代码,注册ip.list, ip.add和ip.del方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
module
RPC
module
Ip
#RPC_LIST used for regsiter rpc_call
RPC_LIST
= %w(list add del)
def
list
$white_lists
end
def
add(ip)
if
ip =~ /^((
25
[
0
-
5
]|
2
[
0
-
4
]\d|[
0
-
1
]?\d\d?)\.){
3
}(
25
[
0
-
5
]|
2
[
0
-
4
]\d|[
0
-
1
]?\d\d?)$/
$white_lists
<< ip
write_to_file
return
"succ"
else
return
"fail"
end
end
def
del(ip)
if
$white_lists
.include?(ip)
$white_lists
.delete ip
write_to_file
return
"succ"
else
return
"fail"
end
end
def
write_to_file
File
.open(IP_yml,
"w"
)
do
|f|
$white_lists
.uniq.
each
{|i| f <<
"- #{i}\n"
}
end
end
end
end
|
。
DSL——使用instance_eval 。
instance_eval是ruby语言中的瑞士军刀,特别是支持DSL方面。 我们来看一下chef(一个开源的自动化部署工具)中设置文件模板的API:
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class
ChefDSL
def
template(path, &block)
TemplateDSL.
new
(path, &block)
end
end
class
TemplateDSL
def
initialize(path, &block)
@path
= path
instance_eval &block
end
def
source(source);
@source
= source;
end
def
owner(owner);
@owner
= owner;
end
def
mode(mode);
@mode
= mode;
end
end
|
。
上面这个小技巧使得TemplateDSL对象可以应用block,和在自己的scope一样。block可以访问和调用TemplateDSL中的变量和方法.
如果没有使用instance_eval,如下面的代码,ruby就会抛出一个NoMethodError,因为source、owner、mode无法在block中被访问到.
。
当然也可以使用yeild传递变量的方式实现,但没有instance_eval简洁和灵活.
命令行交互——使用instance_eval 。
命令行交互,可以采用highline这个gem. 但highline在有些方面不能满足我的需求,比如类似上面介绍的chef template功能,达到的效果如下,大大简化了重复代码:
。
#运行时显示结果如下: Check some frigga failed, skip failed host and continue deploy? [yes/quit] #输入yes继续,输入quit退出 。
。
实现代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
require
'colorize'
class
Tip
def
self
.ask(stat =
true
, &block)
new
(&block).ret
if
stat ==
true
end
attr_reader
:ret
def
initialize(&block)
@opt
= []
@caller
= {}
@banner
=
""
@ret
=
false
self
.instance_eval(&block)
print
"#{@banner} [#{@opt.join('/')}]: "
.light_yellow
loop
do
x = gets.chomp.strip.to_sym
if
@opt
.include?(x)
@ret
= (
@caller
[x].call
if
@caller
.key?(x) )
if
@ret
==
:retry
print
"\n#{@banner} [#{@opt.join('/')}]: "
.light_yellow
next
else
return
@ret
end
else
print
"input error, please enter [#{@opt.join('/')}]: "
.light_yellow
end
end
end
def
on(opt, &block)
@opt
<< opt
@caller
[opt] = block
if
block_given?
end
def
banner(str)
@banner
= str
end
end
|
最后此篇关于ruby元编程实际使用实例的文章就讲到这里了,如果你想了解更多关于ruby元编程实际使用实例的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有两个维度 DimFlag 和 DimPNL 以及一个事实表 FactAmount 。我正在寻找:当 pnl 是 stat(Is Stat=1) 时:sum (Actual x FlagId)对于
我想对包含其部分内容的文本字段执行简单搜索,但我不知道从哪里开始。我基本上想要人们对“包含搜索”的期望。如果我在 issue 中搜索 345 ,我会想要这个结果: 123456 234567 3456
我在 VBE 的 C# 插件中有这段代码(强调“VBE”:它不是 MS-Office 插件): public abstract class HostApplicationBase : IHostApp
我有一个 ImageView,它显示来自资源的图像。ImageView 的宽度是固定的 (60dp)。高度设置为 wrap_content。调整图像大小以适合此宽度(节省宽高比 - 这很完美) 问题是
我正在建立一个网站,但遇到了一个问题:谷歌浏览器开发者工具中的背景以较低/较高的分辨率延伸。当我直接从手机打开网站时,背景不适合屏幕,只是“剪切”了背景。 这是网站:https://feargames
好吧,首先,这是 HTML 模板: ... ... ... ... 如您所见,页面位于标题下方,并且通过 JS 代码可见
我读到了 BK-trees (Burkhard-Keller-Trees) 几个月前,据说这是一种保存您想通过距离度量再次读取的内容的好方法。因此,在每种情况下,您都希望通过相似性检索某些内容。 然而
在 python 中,很容易根据字符数用空格填充字符串。例如: print "aaa".ljust(10) + "end" print "www".ljust(10) + "end" 输出是: aaa
我的问题不是特定于编程语言的,而是更通用的问题,以了解人们的思维方式。 通常在大型开发公司中,每项工作都有特定的角色,例如程序员和架构师。因此架构师的观点是拥有完美的架构师和解决方案设计,另一方面程序
我想将数据传递给 then 方法,但是当我通过给它 this.passedResolve 来执行此操作时,它会得到 undefined function Promises(callback){
我希望使用 Erlang/Elixir 在金融市场创建一个平台即服务。我将在金融市场提供 AWS lambda 风格的函数,但我计划向客户分发我自己的基于 ARM 的硬件终端(基于 Nvidia Je
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
我已经看到很多代码,这些代码使用Runnable的循环时间来实现某些计时器/超时。问题是,如果有人决定更改此Runnable的循环时间,则计时器将不正确。 例: #define FOO_TIMER_1
当我将 WPF DataGrid 的 ColumnHeaderHeight 设置为 Auto (double.NaN) 时,如何获取列标题的实际呈现高度? 我似乎无法在 DataGrid 类中找到该属
目前最实用的png修复方法是什么?轻量级,支持背景重复和背景位置。 最佳答案 IE7.JS在我看来: IE7.js is a JavaScript library to make Microsoft
我已经进行了长时间的搜索并尝试了常见的嫌疑人,但现在是寻求帮助的时候了。 我的 Android Activity 非常愉快地从 SQLite 加载 EditText、Spinner 和 CheckBo
因此,我在 MySQL 全文中创建精确搜索时遇到了一些困难。 在我的数据库中,我正在尝试查找标题中包含特定关键字的职位。 所以我可以尝试 WHERE MATCH(jobTitle) AGAINST (
我正在尝试将 JavaScript 包含到一个表单应用程序中,该应用程序从现场收集施工数据。我已经用谷歌搜索了这个废话,但我无法弄清楚将 html 元素保存在数组中是否合法(或者我的语法是否正确)。
我知道有六种方法可以获取 session.save_path 指令的值(phpinfo()、session_save_path()等),但当值为空字符串时(默认情况下为空字符串),实际路径可以是多个位
我知道 npm 库在安装时可以在分层树中安装同一库的多个版本,如下所示: a@0.1.0 -> b@1.0 -> c@2.0 -> b@2.0 在上面,版本0.1.0的包a被拉入
我是一名优秀的程序员,十分优秀!