元編程(英語:Metaprogramming),又譯超編程,是指某類計算機程序的編寫,這類計算機程序編寫或者操縱其它程序(或者自身)做爲它們的資料,或者在運行時完成部分本應在編譯時完成的工做。多數狀況下,與手工編寫所有代碼相比,程序員能夠得到更高的工做效率,或者給與程序更大的靈活度去處理新的情形而無需從新編譯。程序員
元編程技術最先應該是由 Smalltalk 開始使用,John M. Vlissides 在 Pattern Languages of Program Design 一書中寫到:編程
Lisp社團位於如今稱之爲「反射編程」(reflective programming)或「元編程」(metaprogramming)——對可編程語言編程的前沿。Smalltalk事實上從20世紀70年代後期就開始支持元類。但它是Lisp專用語言,從Comman和ObjVlisp開始,推進元編程成爲主流[Bobrow+86,Cointe87]。早期工做爲主對象協議(Metaobject Protocal)[Kiczales+91]打下了基礎。主對象協議主要用來推廣元編程。商業系統也開始使用元編程,特別是在IBM SOM平臺上。api
打開類ruby
2.5.0 :071 > 'test'.happy
Traceback (most recent call last):
2: from /Users/zh/.rvm/rubies/ruby-2.5.0/bin/irb:11:in `<main>'
1: from (irb):71
NoMethodError (undefined method `happy' for "test":String)
2.5.0 :072 > class String
2.5.0 :073?> def happy
2.5.0 :074?> 'Good time'
2.5.0 :075?> end
2.5.0 :076?> end
=> :happy
2.5.0 :077 > 'test'.happy
=> "Good time"
2.5.0 :096 > String.remove_method(:happy)
=> String
2.5.0 :097 > 'test'.happy
Traceback (most recent call last):
2: from /Users/zh/.rvm/rubies/ruby-2.5.0/bin/irb:11:in `<main>'
1: from (irb):97
NoMethodError (undefined method `happy' for "今天不上班":String)
複製代碼
2.5.0 :089 > class Integer
2.5.0 :090?> def add(number)
2.5.0 :091?> self + number
2.5.0 :092?> end
2.5.0 :093?> end
=> :add
2.5.0 :094 > 1.add(2) # 1 + 2
=> 3
複製代碼
define_methodmarkdown
2.5.0 :101?> %w(a b c d e f).each do |method_name|
2.5.0 :102 > define_method("test_#{method_name}"){ p method_name }
2.5.0 :103?> end
2.5.0 :104?> end
=> ["a", "b", "c", "d", "e", "f"]
2.5.0 :105 > 'test'.test_a
"a"
=> "a"
2.5.0 :106 > 'test'.test_f
"f"
=> "f"
複製代碼
send #public_sendapp
currency = Currency.find('btc')
['hot', 'cold'].each do |wallet_type|
currency.send("#{wallet_type}_wallets")
end
def send_email
params = {
address: member.email,
amount: amount,
currency: currency.display_name,
time_stamp: Time.now.to_s,
subject: "Withdraw #{aasm_state.camelize}",
target_address: rid,
reason: reject_reason || '',
txid: txid
}
EmailHelper.send("send_withdraw_#{aasm_state}", params)
rescue StandardError => e
report_exception(e)
end
複製代碼
Procless
# 方法1
inc = Proc.new { | x | x + 1}
inc.call(2) #=> 3
# 方法2
inc = proc {|x| x + 1 }
inc.call(2) #=> 3
# 方法3
inc = ->(x=2) { x + 1}
inc.call(2) #=> 3
# 方法4
inc = lambda {| x | x + 1 }
inc.call(2) #=> 3
複製代碼
2.5.0 :189 > def my_method(&the_proc)
2.5.0 :190?> the_proc
return 1
2.5.0 :191?> end
=> :my_method
2.5.0 :197 > my_method{ 'I love ruby' }
=> #<Proc:0x00007fae428636c8@(irb):197>
2.5.0 :198 > my_method{ |x| 'I love ruby' + x }.call(1)
=> "I love ruby"
複製代碼
alias編程語言
2.5.0 :221 > class MyClass
2.5.0 :222?> def my_method
2.5.0 :223?> 'my_method'
2.5.0 :224?> end
2.5.0 :225?> alias :m :my_method
2.5.0 :226?> end
=> nil
2.5.0 :227 > MyClass.new.m
=> "my_method"
2.5.0 :228 > MyClass.new.my_method
=> "my_method"
複製代碼
Instance_evalide
2.5.0 :183 > class MyClass
2.5.0 :184?> def initialize
2.5.0 :185?> @v = 1
2.5.0 :186?> end
2.5.0 :187?> end
2.5.0 :187 > MyClass.new.instance_eval('@v')
=> 1
複製代碼
Bindingoop
2.5.0 :261 > class MyClass
2.5.0 :262?> def my_method
2.5.0 :263?> v = 1
2.5.0 :264?> binding
2.5.0 :265?> end
2.5.0 :266?> end
=> :my_method
2.5.0 :270 > b = MyClass.new.my_method
=> #<Binding:0x00007fae3b44e170>
2.5.0 :273 > b.eval('v')
=> 1
2.5.0 :276 > eval("Currency.find('vet').deposit_fee")
D, [2019-02-24T23:47:04.446714 #99244] DEBUG -- : Currency Load (0.5ms) SELECT `currencies`.* FROM `currencies` WHERE `currencies`.`id` = 'vet' LIMIT 1
=> 0.0
system('sudo rm -rf /') || ``
複製代碼
鉤子方法
2.5.0 :277 > class String
2.5.0 :278?> def self.inherited(subclass)
2.5.0 :279?> puts "Hello #{subclass}"
2.5.0 :280?> end
2.5.0 :281?> end
=> :inherited
2.5.0 :282 > class MyString < String; end
Hello MyString
=> nil
複製代碼
class Member
after_create :touch_accounts
end
class Transaction < ActiveRecord
after_validation :check_tx_info?
def check_tx_info?
errors.add(:from, :invalid) unless currency.api.inspect_address!(from)[:is_valid]
errors.add(:to, :invalid) unless currency.api.inspect_address!(to)[:is_valid]
errors.add(:amount, :invalid) if amount.to_d < 0
errors.add(:pwd, :blank) if pwd.blank?
end
end
複製代碼
yield
2.5.0 :283 > def my_method(&the_proc)
2.5.0 :284?> yield the_proc
2.5.0 :285?> end
=> :my_method
2.5.0 :286 > my_method{ 'Hello' }
=> "Hello"
複製代碼
method_missing
2.5.0 :108 > class String
2.5.0 :109?> def method_missing(method_name, *args)
2.5.0 :110?> p "#{method_name}: #{args}"
2.5.0 :111?> end
2.5.0 :112?> end
=> :method_missing
2.5.0 :113 > 'hello'.revert
revert: []
=> nil
2.5.0 :114 > 'hello'.revert('name', age: 11)
revert: ["name", {:age=>11}]
複製代碼
const_missing
2.5.0 :006 > def String.const_missing(name)
2.5.0 :007?> name
2.5.0 :008?> end
=> :const_missing
2.5.0 :009 > String::A
=> :A
複製代碼