看完今天的文章,自己试着在专案写动态写法後,读者们会发现今天讲的东西很实用。我们可以透过动态的写法,省去相当多程序码。
define_method
是目前最常提到的用法,该用法可以动态的宣告方法
class Person
define_method :greeting, -> { puts 'Hello!' }
end
Person.new.greeting # => Hello!
上面的例子中,greeting
等同於以下写法。
class Person
def greeting
puts 'Hello!'
end
end
⭐️ 接着我们来说明我在寄信服务上的动态方法
class NotificationMailer < ApplicationMailer
# 所有方法
MAIL_METHODS = %w[
order_init order_need_pay order_canceled_by_customer
order_canceled_by_user order_canceled_not_pay
order_shipped order_arrived order_ship_failed
invoice_issued return_applied return_failed return_partial_failed return_done
maintain_quoted register member_upgrade member_renewal expiring_accumulate
member_expiring cart acquire_rebate expiring_credit_point maintain_back
]
MAIL_METHODS.each do |key|
define_method(key) do |email, instance, title = nil|
@instance = instance
mail(to: email, subject: title || send("#{key}_title"))
end
end
end
上面为mailer
的方法,由於不同的寄信方式内容大致上相同,就可以使用define_method
。其中 define_method
的email, instance, title = nil
,都是被带入的参数。上述的方式也可以用method_missing
实现,method_missing
在後面会介绍到,不过这里用define_method
会比较直观。
在我刚开始使用send
的时候,我问自己一个问题?这个问题是Ruby
的方法是Symbol
吗?上网查了以後,发现很多人都有类似的问题。确实symbol
在Ruby
的世界中占取的object_id
相同,所以也可以想像得到,我们可以使用send
搭配symbol
做动态的呼叫方法
# 意思相同
1 + 1 = 2
1.send(:+, 1)
# 意思相同
"We are the world".upcase
"We are the world".send(:.upcase)
# 使用客制化 send
class Klass
def hello(*args)
"Hello " + args.join(' ')
end
end
k = Klass.new
k.send(:hello, "gentle", "readers") #=> "Hello gentle readers"
send
的第一个参数是方法,第二个以後全部都是带进来的参数。接着我们讲send
如何搭配其他方法!
send
& respond_to?
的搭配简直是绝妙。以下的写法A,可以使用写法B代替
print "Search for: "
request = gets.chomp
# 写法A
if request == "writer"
puts book.writer
elsif request == "press"
puts book.press
elseif request == "date"
puts book.date
else
puts "Input error"
end
# 写法b
if book.respond_to?(request)
puts book.send(request)
else
puts "Input error"
end
⭐️ 接着我们看respond_to?
的好处?使用respond_to?
被使用以後,就不必担心会有undefined method
的错误。
obj = Object.new
if obj.respond_to?("talk")
obj.talk
else
puts "Sorry, object can't talk!"
end
# 若找不到talk,也不会跳出undefined method 'talk' for #<Object:0x12345678> (NoMethodError)的错误
⭐️ 学习rails
的读者们千万要记住, respond_to
是Rails 控制器的用法,和 respond_to?
完全是不一样的概念喔!
def index
@people = Person.find(:all)
respond_to do |format|
format.html
format.json { render :json => @people.as_json }
end
end
⭐️ 以下为send
与 define_method
的搭配。
class A
def create_method(name, &block)
self.class.send(:define_method, name, &block)
end
end
a = A.new
a.create_method(:run) { "Running Man" }
a.run
#=> "Running Man"
send
和define_method
的搭配方法,确实可以玩很多不同的变化 ?,後面介绍的method_missing
,就会搭配send
和define_method
回传self
在Ruby
是很常见的写法,此外符合设计流程的Builder Pattern
class Salad
def initialize
@ingredients = []
end
def add_veg
@ingredients << :vegatable
self
end
end
salad = Salad.new #=> #<Salad:0x00007fc42151a3a0 @ingredients=[]>
salad.add_veg #=> #<Salad:0x00007fc42151a3a0 @ingredients=[:vegatable]>
salad.instance_eval {@ingredients} #=> [:vegatable]
salad.add_veg #=> #<Salad:0x00007fc42151a3a0 @ingredients=[:vegatable, :vegatable]>
salad.instance_eval {@ingredients} #=> [:vegatable, :vegatable]
class Stack
def initialize
@store = Array.new
end
def push(element)
@store.push(element)
self
end
def pop
@store.pop
self
end
end
stack = Stack.new
#=> #<Stack:0x00007fc42dd78ab8 @store=[]>
stack.push '1'
#=> #<Stack:0x00007fc42dd78ab8 @store=["1"]>
tack.push '1'
#=> #<Stack:0x00007fc42dd78ab8 @store=["1", "1"]>
stack.push '1'
#=> #<Stack:0x00007fc42dd78ab8 @store=["1", "1", "1"]>
stack.pop
#=> #<Stack:0x00007fc42dd78ab8 @store=["1", "1"]>
stack.pop
#=> #<Stack:0x00007fc42dd78ab8 @store=["1"]>
stack.pop
#=> #<Stack:0x00007fc42dd78ab8 @store=[]>
以上面的例子来讲,我们做了多次push
, pop
,实体变数删改元素。回传self
,可以让我们可以连锁使用push
, pop
的动作,达到改动object
的目的
在Ruby当中,这不算是陌生的方法,有时候在报错的时候都会看到。
除了报错以外,我们还可以用method_missing做一些好玩的事情:
class Developer
def method_missing method, *args, &block
# 若 prefix 不为 it_day ,则继承父层(预设)的 method_missing ➡️ 报错
return super method, *args, &block unless method.to_s =~ /^it_\w+/
self.class.send(:define_method, method) do
"我要挑战IT铁人赛主题为 " + method.to_s.gsub(/^it_/, '').to_s + " 的文章"
end
self.send method, *args, &block
end
end
itday = Developer.new
itday.it_rails #=> "我要挑战IT铁人赛主题为 rails 的文章"
itday.it_javascript #=> "我要挑战IT铁人赛主题为 javascript 的文章"
当我们在写条件句,或者case when
的时候,可以想想可以用什麽动态的写法省去多余的code。Rails
本身是个遵照惯例的框架,所以熟悉一段时间 Rails
之後,不难发现其实很多规律性的地方都可以使用动态生成的写法来作替代。
接着我们来复习目前已经讲了几个设计流程
从Day18-22,我们会开始讲解画面。
可视化编程游戏引擎 可视化编程是指可以把程序代码视觉化 不需要写程序代码就可以编写程序逻辑,降低了...
Lens - K8s上好用的client端程序 除了使用kubectl cli去操作k8s外,也有u...
今天是30天程序语言研究的第十八天,由於深度学习老师多让我们上了python的进阶课程里面包括之前没...
昨天谈到 write skew 和 phantoms ,是 2 种特别难重现的 竞争条件 (race...
在前面我们已经稍微了解如何把资料抓取到Elasticsearch,但是单纯用api来查询资料,对使用...