承续昨天的实作,今天就来补上 Routing 的最後一个步骤
还记得我们怎麽实作 MiniSinatra 的 DSL
吗?
# MiniSinatra
def get(path, &block)
MiniSinatra.application.add_route('GET', path, &block)
end
get '/' do
'hello world !'
end
是不是跟我们的 just_do 里面的 routes.rb 很像?
Mavericks.application.routes.draw do
root to: 'tasks#index'
resources :tasks
end
透过这样的判断,我们知道 root
和 resources
其实也就是一个 mehtod,但为什麽这些 method 可以被包在一个 block 里面去执行呢?这就是我们今天会提到的一个很重要的观念 - instance_eval
先来看看一个范例
class MyClass
def initialize
@v = 1
end
end
obj = MyClass.new
obj.instance_eval do
puts self
puts @v
end
这里我们建立了一个 MyClass
,在里面存放了一个实体变数叫 @v
并且给予 1
的值,接着 new 一个 MyClass
的物件以後,执行 instance_eval
,里面会印出什麽呢?
答案是
#<MyClass:0x00007f85a3033538>
1
从这个例子我们可以知道,在 instance_eval
这个 block 里面执行的环境会是「这个物件」本身,所以可以透过这样的方式来取得「这个物件」的内容,当然也可以为「这个物件」定义方法
像是这样
class MyClass
def initialize
@v = 1
end
end
obj = MyClass.new
obj.instance_eval do
def v
@v
end
end
puts obj.v
可以看到我们一开始并没有定义 attr_accessor
,但之後透过 instance_eval
来替「这个物件」加上,为什麽我一直强调「这个物件」呢,因为用 instance_eval
定义出来的方法,其他物件并不能共用
class MyClass
def initialize
@v = 1
end
end
obj = MyClass.new
obj2 = MyClass.new
obj.instance_eval do
def v
@v
end
end
puts obj.v
# 1
puts obj2.v
# undefined method `v'
所以如果要定义出,不管其他物件也可以使用的方法,就要用另一个很类似的 method,只是作用在 class 上的 class_eval
class MyClass
def initialize
@v = 1
end
end
MyClass.class_eval do
def v
@v
end
end
obj = MyClass.new
obj2 = MyClass.new
puts obj.v
puts obj2.v
至於为什麽 instance method
,反而要用 class_eval
来定义,而不是用 instance_eval
?
那是因为 instance method
实际存放的位置是在 Class
上面,只有定义在 Class
上,才可以让每一个 new 出来的物件做共享,物件里面存放的只有实体变数
刚刚我们已经说明了 instance_eval
,现在再来看看 draw
def draw(&block)
mapper = Mapper.new(self)
mapper.instance_eval(&block)
end
就可以知道,我们利用 instance_eval,来去执行里面的 Mapper
物件里面的 method,而在 Mapper
,就是我们的各种定义 DSL 语法的地方
# mavericks/lib/action_dispatch/routing/mapper.rb
module ActionDispatch
module Routing
class Mapper
def initialize(route_set)
@route_set = route_set
end
def get(path, to:, as: nil)
# to => "controller#index"
controller, action = to.split("#")
@route_set.add_route("GET", path, controller, action, as)
end
def root(to:)
get "/", to: to, as: 'root'
end
def resources(plural_name)
get "/#{plural_name}", to: "#{plural_name}#index", as: plural_name.to_s
get "/#{plural_name}/new", to: "#{plural_name}#new",
as: "new_" + plural_name.to_s.singularize
get "/#{plural_name}/show", to: "#{plural_name}#show",
as: plural_name.to_s.singularize
end
end
end
end
另外可以看到,我们在初始化时传了一个 route_set
的 instance,是因为我们需要借助 route_set
的 add_route
method 来将规则加到 @routes,让之後在比对规则时可以取出
因为篇幅的关系,这里只有实作 get 的部分,接下来一样别忘记做 autoload
# mavericks/lib/action_dispatch.rb
module ActionDispatch
module Routing
autoload :RouteSet, "action_dispatch/routing/route_set"
autoload :Mapper, "action_dispatch/routing/mapper"
end
end
并且在 all.rb
里面把原有的 routing.rb
拿掉,换成新的 action_dispatch
# mavericks/lib/mavericks/all.rb
require 'erubi'
require 'yaml'
require "mavericks"
require "active_support"
require "active_record"
require "action_controller"
require "action_dispatch"
接着回到 just_do,除了新增 routes.rb
以外,其他程序码不需要更动
# just_do/config/routes.rb
Mavericks.application.routes.draw do
root to: 'tasks#index'
resources :tasks
end
然後打开浏览器测试看看,没问题的话,网站应该还是会正常运作!
Mavericks github: https://github.com/apayu/mavericks
>>: [Day 27] 微探讨 Pure pipe 与 Impure pipe
想要在 WordPress 上面播放影片,有 2 种方法。 第 1 种是直接上传影片档案,例如上传 ...
前言 昨天文章有提到 Grid 其实还有东西没讲完, 所以今日文章就定调为把 Grid 讲完, 然後...
昨天说的是 Android 今天我们来聊聊如何打包 ios, 但因为没有开发帐号,所以就只说 rea...
综合过去所学 今天要来练习的是「动态进度条」 废话不多说直接练习吧! 程序码: #include&l...
今天的话来简单介绍一下CLI的各个资料吧。 node_modeules :node 相关的套件 pu...