zoukankan      html  css  js  c++  java
  • LightTable的结构(二)

    这节主要研究下object的一个属性,behaviors

    定义一个behavior需要提供name,trigger,reaction

    (behavior ::on-close-destroy
              :triggers #{:close}
              :reaction (fn [this]
                          (object/raise this :destroy)))
    

    在创建object的时候传入

    (object/object* ::user.hello
                    :tags [:user.hello]
                    :behaviors [::on-close-destroy]
                    :init (fn [this]
                            (hello-panel this)))
    

    在object/object*和object/create的时候都可以传入behavior

    那么怎么触发behavior呢

    (object/raise app :closing)
    
    (defn raise*
      ([obj reactions args] (raise* obj reactions args nil))
      ([obj reactions args trigger]
       (doseq [r reactions
               :let [func (:reaction (->behavior r))
                     args (if (coll? r)
                            (concat (rest r) args)
                            args)
                     meta (if (coll? r)
                            (meta r)
                            {})]
               :when func]
         (try
         (with-time
           (binding [*behavior-meta* meta]
             (apply func obj args))
           (when-not (= trigger :object.behavior.time)
             (raise obj :object.behavior.time r time trigger)))
           (catch js/Error e
             (safe-report-error (str "Invalid behavior: " (-> (->behavior r) :name)))
             (safe-report-error e)
             )
           (catch js/global.Error e
             (safe-report-error (str "Invalid behavior: " (-> (->behavior r) :name)))
             (safe-report-error e)
             )))))
    
    (defn raise [obj k & args]
      (let [reactions (-> @obj :listeners k)]
        (raise* obj reactions args k)))
    

    可以看出,object/raise会从obj的:listeners中获取对应trigger的reactions

    object/raise*中,对这些reactions进行执行,那么behavior是如何变成:listener的呢,注意到 object/handle-redef 会使用update-listeners

    (defn handle-redef [odef]
      (let [id (::type odef)]
        (doseq [o (instances-by-type id)
                :let [o (deref o)
                      args (:args o)
                      old (:content o)
                      behs (set (:behaviors o))
                      inst (@instances (->id o))
                      neue (when (:init odef)
                             (apply (:init odef) inst args))
                      neue (if (vector? neue)
                             (crate/html neue)
                             neue)]]
          (merge! inst {:tags (set/union (:tags o) (:tags odef))
                                          :behaviors (set/union behs (set (:behaviors odef)))
                                          :content neue})
          (merge! inst (update-listeners inst))
          (when (and old neue)
            (replace-with old neue))
          (raise inst :redef))
        id))
    
    (defn object* [name & r]
      (-> (apply make-object* name r)
          (store-object*)
          (handle-redef)))
    

    update-listeners利用->triggers将behavior转换成对应的 trigger,存入:listeners

    (defn update-listeners
      ([obj] (update-listeners obj nil))
      ([obj instants]
       (let [cur @obj
             behs (set (concat (:behaviors cur) (tags->behaviors (:tags cur))))
             trigs (->triggers behs)
             ;;We need to load new JS files here because they may define the behaviors that we're meant to
             ;;capture. If we have a load, then load and recalculate the triggers to pick up those newly
             ;;defined behaviors
             trigs (if (:object.instant-load trigs)
                     (do
                       (raise* obj (:object.instant-load trigs) nil :object.instant-load)
                       (->triggers behs))
                     trigs)
             trigs (if instants
                     trigs
                     (dissoc trigs :object.instant :object.instant-load))]
         ;;deref again in case :object.instant-load made any updates
         (assoc @obj :listeners trigs))))
    
    (defn ->triggers [behs]
      (let [result (atom (transient {}))]
        (doseq [beh behs
                t (:triggers (->behavior beh))]
          (swap! result assoc! t (conj (or (get @result t) '()) beh)))
        (persistent! @result)))
    

      

    --------------------------------------

    注:

    获取Ref, Atom 和Agent对应的value @ref (deref ref)  

  • 相关阅读:
    工厂模式一
    面向对象的简单理解二
    工厂模式三
    线程的简单学习
    nyoj35 表达式求值
    nyoj305 表达式求值
    poj1298 The Hardest Problem Ever
    poj1363 Rails
    hdu2036 改革春风吹满地
    nyoj467 中缀式变后缀式
  • 原文地址:https://www.cnblogs.com/TLightSky/p/4117826.html
Copyright © 2011-2022 走看看