Sinatra 源码分析 (一):set 系统工作原理 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Mark24
V2EX    Ruby

Sinatra 源码分析 (一):set 系统工作原理

  •  
  •   Mark24 2022-02-14 22:59:28 +08:00 3297 次点击
    这是一个创建于 1332 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我的 BLOG

    前言

    大家好,我是 MARK24 。可以叫我 MARK 。这是我研究 Sinatra 的笔记。

    阅读过程大约 10 分钟。

    基于 Sinatra 2.1.0 进行讨论

    Sinatra v2.1.0 Fork 代码地址

    Sinatra set 介绍

    set 系统可以让 Sinatra 在自身自由的定义 设置相关的变量。

    比如定义模板所在:

    set :views, settings.root + '/templates' 

    定义 session secret:

    set :session_secret, ENV.fetch('SESSION_SECRET') { SecureRandom.hex(64) } 

    等等,非常自由且灵活。

    set 系统这部分的源码恰巧是可以简单修改之后独立工作的。摘要如下:

    # https://github.com/Mark24Code/sinatra-code-review/blob/master/lib/sinatra/base.rb#L1267 def define_singleton(name, cOntent= Proc.new) singleton_class.class_eval do undef_method(name) if method_defined? name String === content ? class_eval("def #{name}() #{content}; end") : define_method(name, &content) end end def set(option, value = (not_set = true), ignore_setter = false, &block) raise ArgumentError if block and !not_set value, not_set = block, false if block if not_set raise ArgumentError unless option.respond_to?(:each) option.each { |k,v| set(k, v) } return self end if respond_to?("#{option}=") and not ignore_setter return __send__("#{option}=", value) end setter = proc { |val| set option, val, true } getter = proc { value } case value when Proc getter = value when Symbol, Integer, FalseClass, TrueClass, NilClass getter = value.inspect when Hash setter = proc do |val| val = value.merge val if Hash === val set option, val, true end end define_singleton("#{option}=", setter) define_singleton(option, getter) # 原始代码放在一个类中, 如果我们想放在单文件执行,需要 改写为 `self.class.method_defined?` 调用到方法 # define_singleton("#{option}?", "!!#{option}") unless method_defined? "#{option}?" define_singleton("#{option}?", "!!#{option}") unless self.class.method_defined? "#{option}?" self end 

    set 源码分析

    Sinatra 内部实现了一套 配置系统,基于一个 DSL 语法 set 。 这是 Sinatra Class 部分初始化之后唯一的初始化的 DSL 。Sinatra 没有做很多复杂的前置工作。

    一致很让我疑惑的是,这里的 getter 、setter 。我们传统理解的 是这样工作的:

     class Sample def initialize() @name end # getter def name @name end # setter def name=(new_name) @name = new_name end end 

    但是 Sinatra 这里似乎是一个循环一样的,你会发现他的 setter 永远在调用 set 这是为什么呢?我一度非常迷惑。

    setter = proc { |val| set option, val, true } 

    我刚开始进入这段是百思不得其解。但事实证明我格局小了。这部分其实根本不是传统的 setter, 我们观察传统的 setter 他的问题是必须要以一个实例变量为依托。所以他才必须写成这样。 如果是下面这样呢?

    class Sample # getter def name "new value" end # setter def name=(new_name) # setter 的逻辑,就是覆盖式定义一个 新的 直接返回新值的 getter re_define_name_getter(new_name) end end 

    直接伪代码,我们每次调用 setter ,setter 的任务不是去修改一个 中间值,而是每次去重新定义 新的 getter 方法,定义的时候就塞入新的值。

    这样依然保持了 getter 的功能!豁然开朗!

    Sinatra 的 set 系统就是这样工作的,不论是 set 函数定义本身,还是 set 内部调用的 set ,还是用户最终在外部书写 set xxx, new_value 最终殊途同归的进入 set option, value, true 然后都会走到最后一部分,重新定义三个方法。

     define_singleton("#{option}=", setter) define_singleton(option, getter) define_singleton("#{option}?", "!!#{option}") unless method_defined? "#{option}?" 

    setter 方法的作用就是调用 set 自身,这样只要被调用,时间上可以完成了一种循环。闭环调用(原谅我用了闭环这个词 :P ) getter 方法 是以新的值直接返回,respond_to 方法同理,以新值计算返回。

    补充

    1.定义处有趣的写法 value = (not_set = true)

    def set(option, value = (not_set = true), ignore_setter = false, &block) # .... end 

    可以通过实验证实这种写法的特点是:

    如果 value 赋值 比如是 99 ,那么 value = 99, not_set = nil

    如果 value 没有赋值, 那么 value = not_set = true

    这里主要是没有赋值,not_set 开始发挥逻辑上的作用。

    我的 BLOG

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2825 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 13:35 PVG 21:35 LAX 06:35 JFK 09:35
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86