Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lets enjoy creating gems

makicamel
October 03, 2020

Lets enjoy creating gems

継承とメタプログラミング満載なアプリケーションコードでもアクションとフィルタに悩まないためのGemを作った話
- 2020.10.03. Kaigi on Rails STAY HOME Edition

makicamel

October 03, 2020
Tweet

More Decks by makicamel

Other Decks in Programming

Transcript

  1. ˞೥݄೔ݱࡏ "/%1"% $ rails stats +----------------------+--------+--------+---------+---------+-----+-------+ | Name | Lines

    | LOC | Classes | Methods | M/C | LOC/M | +----------------------+--------+--------+---------+---------+-----+-------+ | Controllers | 66567 | 52928 | 1030 | 5473 | 5 | 7 | +----------------------+--------+--------+---------+---------+-----+-------+ $ find . -name application_controller.rb | wc -l 3 ׂ͕ ApplicationController # => 325
  2. •֤֊૚͝ͱʹ application_controller.rb ͕͍Δ •֤ ApplicationController ͸ ਌֊૚ͷ ApplicationController Λܧঝ ͞Βʹ

    •ڞ௨ॲཧΛϞδϡʔϧԽ֤ͯ͠ॴͰ include •ϝλϓϩຬࡌ "/%1"% ˞೥݄೔ݱࡏ
  3.   [2020-09-27T03:25:43.018298 #1] [“APPLIED",:set_turbolinks_location_header_from _session, “/usr/local/bundle/gems/turbolinks-… redirection.rb”, 43] [2020-09-27T03:25:43.019410

    #1] ["APPLIED", :verify_authenticity_token, “/usr/ local/bundle/gems/actionpack-…/ request_forgery_protection.rb”, 211] [2020-09-27T03:25:43.021131 #1] ["APPLIED", :require_login, “/myapp/app/ controllers/awesome_controller.rb", 17] [2020-09-27T03:25:43.022063 #1] ["NO_APPLIED", :set_awesome, “/myapp/app/ controllers/awesome_controller.rb", 25] [2020-09-27T03:25:43.023716 #1] ["APPLIED", :with_readonly, “/myapp/app/ controllers/awesome_controller.rb", 21] [2020-09-27T03:25:43.025547 #1] ["ACTION", :index, “/myapp/app/controllers/ awesome_controller.rb", 7] [2020-09-27T03:25:43.026297 #1] ["APPLIED", :with_readonly, “/myapp/app/ controllers/awesome_controller.rb", 21] [2020-09-27T03:25:43.027203 #1] ["APPLIED", :store_location, “/myapp/app/ controllers/awesome_controller.rb", 27] [2020-09-27T03:25:43.030074 #1] ["APPLIED", :verify_same_origin_request, “/usr/ local/bundle/gems/actionpack-…/ request_forgery_protection.rb”, 240] class AwesomeController < ApplicationController before_action :require_login before_action :set_awesome, only: :show around_action :with_readonly after_action :store_location def index # ... end def show # ... end private def require_login # ... end # ... ˞ϩάͷҰ෦Λলུ͍ͯ͠·͢ɻྫ͸3&"%.&ʹ͋Γ·͢ɻ IUUQTHJUIVCDPNNBLJDBNFMBDUJPO@USBDFS ActionTracer ΞΫηε࣌ʹϑΟϧλΛॻ͖ग़͢
  4.  ˞ϩάͷҰ෦Λলུ͍ͯ͠·͢ɻྫ͸3&"%.&ʹ͋Γ·͢ɻ IUUQTHJUIVCDPNNBLJDBNFMBDUJPO@USBDFS ActionTracer •ΞϓϦέʔγϣϯίʔυ͚ͩͰ͸ͳ͘ GemͷϑΟϧλ΋هࡌ [2020-09-27T03:25:43.018298 #1] [“APPLIED",:set_turbolinks_location_header_from _session,

    “/usr/local/bundle/gems/turbolinks-… redirection.rb”, 43] [2020-09-27T03:25:43.019410 #1] ["APPLIED", :verify_authenticity_token, “/usr/ local/bundle/gems/actionpack-…/ request_forgery_protection.rb”, 211] [2020-09-27T03:25:43.021131 #1] ["APPLIED", :require_login, “/myapp/app/ controllers/awesome_controller.rb", 17] [2020-09-27T03:25:43.022063 #1] ["NO_APPLIED", :set_awesome, “/myapp/app/ controllers/awesome_controller.rb", 25] [2020-09-27T03:25:43.023716 #1] ["APPLIED", :with_readonly, “/myapp/app/ controllers/awesome_controller.rb", 21] [2020-09-27T03:25:43.025547 #1] ["ACTION", :index, “/myapp/app/controllers/ awesome_controller.rb", 7] [2020-09-27T03:25:43.026297 #1] ["APPLIED", :with_readonly, “/myapp/app/ controllers/awesome_controller.rb", 21] [2020-09-27T03:25:43.027203 #1] ["APPLIED", :store_location, “/myapp/app/ controllers/awesome_controller.rb", 27] [2020-09-27T03:25:43.030074 #1] ["APPLIED", :verify_same_origin_request, “/usr/ local/bundle/gems/actionpack-…/ request_forgery_protection.rb”, 240] Turbolinks Rails ΞϓϦέʔγϣϯ ݺ͹ΕͨΞΫγϣϯ
  5.  ˞ϩάͷҰ෦Λলུ͍ͯ͠·͢ɻྫ͸3&"%.&ʹ͋Γ·͢ɻ IUUQTHJUIVCDPNNBLJDBNFMBDUJPO@USBDFS ActionTracer •ϑΝΠϧύεɺߦ਺ [2020-09-27T03:25:43.018298 #1] [“APPLIED",:set_turbolinks_location_header_from _session, “/usr/local/bundle/gems/turbolinks-…

    redirection.rb”, 43] [2020-09-27T03:25:43.019410 #1] ["APPLIED", :verify_authenticity_token, “/usr/ local/bundle/gems/actionpack-…/ request_forgery_protection.rb”, 211] [2020-09-27T03:25:43.021131 #1] ["APPLIED", :require_login, “/myapp/app/ controllers/awesome_controller.rb", 17] [2020-09-27T03:25:43.022063 #1] ["NO_APPLIED", :set_awesome, “/myapp/app/ controllers/awesome_controller.rb", 25] [2020-09-27T03:25:43.023716 #1] ["APPLIED", :with_readonly, “/myapp/app/ controllers/awesome_controller.rb", 21] [2020-09-27T03:25:43.025547 #1] ["ACTION", :index, “/myapp/app/controllers/ awesome_controller.rb", 7] [2020-09-27T03:25:43.026297 #1] ["APPLIED", :with_readonly, “/myapp/app/ controllers/awesome_controller.rb", 21] [2020-09-27T03:25:43.027203 #1] ["APPLIED", :store_location, “/myapp/app/ controllers/awesome_controller.rb", 27] [2020-09-27T03:25:43.030074 #1] ["APPLIED", :verify_same_origin_request, “/usr/ local/bundle/gems/actionpack-…/ request_forgery_protection.rb”, 240]
  6.  ˞ϩάͷҰ෦Λলུ͍ͯ͠·͢ɻྫ͸3&"%.&ʹ͋Γ·͢ɻ IUUQTHJUIVCDPNNBLJDBNFMBDUJPO@USBDFS ActionTracer •ͦͷϑΟϧλ͕ ࣮ࡍʹద༻͞Ε͔ͨ൱͔ •etc … [2020-09-27T03:25:43.018298 #1]

    [“APPLIED",:set_turbolinks_location_header_from _session, “/usr/local/bundle/gems/turbolinks-… redirection.rb”, 43] [2020-09-27T03:25:43.019410 #1] ["APPLIED", :verify_authenticity_token, “/usr/ local/bundle/gems/actionpack-…/ request_forgery_protection.rb”, 211] [2020-09-27T03:25:43.021131 #1] ["APPLIED", :require_login, “/myapp/app/ controllers/awesome_controller.rb", 17] [2020-09-27T03:25:43.022063 #1] ["NO_APPLIED", :set_awesome, “/myapp/app/ controllers/awesome_controller.rb", 25] [2020-09-27T03:25:43.023716 #1] ["APPLIED", :with_readonly, “/myapp/app/ controllers/awesome_controller.rb", 21] [2020-09-27T03:25:43.025547 #1] ["ACTION", :index, “/myapp/app/controllers/ awesome_controller.rb", 7] [2020-09-27T03:25:43.026297 #1] ["APPLIED", :with_readonly, “/myapp/app/ controllers/awesome_controller.rb", 21] [2020-09-27T03:25:43.027203 #1] ["APPLIED", :store_location, “/myapp/app/ controllers/awesome_controller.rb", 27] [2020-09-27T03:25:43.030074 #1] ["APPLIED", :verify_same_origin_request, “/usr/ local/bundle/gems/actionpack-…/ request_forgery_protection.rb”, 240]
  7. TracePoint •ॲཧΛొ࿥͓͖ͯ͠ɺ֤छΠϕϯτΛ͖͔͚ͬʹ࣮ߦͰ͖Δ •ΠϕϯτྫʢҰ෦ʣ •:line •:call •:return •:c_call •:c_return ࣜͷධՁ Ruby

    Ͱهड़͞Εͨϝιουͷݺͼग़͠ Ruby Ͱهड़͞Εͨϝιουݺͼग़͔͠ΒͷϦλʔϯ C Ͱهड़͞Εͨϝιουͷݺͼग़͠ C Ͱهड़͞Εͨϝιουݺͼग़͔͠ΒͷϦλʔϯ
  8. TracePoint •ॲཧΛొ࿥͓͖ͯ͠ɺ֤छΠϕϯτΛ͖͔͚ͬʹ࣮ߦͰ͖Δ •ΠϕϯτྫʢҰ෦ʣ •:line •:call •:return ࣜͷධՁ Ruby Ͱهड़͞Εͨϝιουͷݺͼग़͠ Ruby

    Ͱهड़͞Εͨϝιουݺͼग़͔͠ΒͷϦλʔϯ ΞϓϦέʔγϣϯίʔυ΋ Rails ͷίʔυ΋۠ผ͞Εͳ͍ ͍͍ײ͡ʹநग़͢ΔͱΑ͍ͷͰ͸
  9. ActiveSupport::Callbacks module ActiveSupport module Callbacks module Conditionals # :nodoc: module

    Filters class Callback #:nodoc:# class CallTemplate # :nodoc: class CallbackSequence # :nodoc: class CallbackChain #:nodoc:# module ClassMethods DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC
  10. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCFEDDDGBDUJPOQBDLMJCBCTUSBDU@DPOUSPMMFSDBMMCBDLTSC module AbstractController module Callbacks # ... included do

    define_callbacks( :process_action, terminator: ->(controller, result_lambda) { result_lambda.call if result_lambda.is_a?(Proc) controller.performed? }, skip_after_callbacks_if_terminated: true ) end # ... AbstractController
  11. module ActiveSupport module Callbacks module Conditionals module Filters class Callback

    class CallTemplate class CallbackSequence class CallbackChain module ClassMethods DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def define_callbacks(*names) options = names.extract_options! names.each do |name| name = name.to_sym set_callbacks name, CallbackChain.new(name, options) module_eval <<-RUBY, __FILE__, __LINE__ + 1 def _run_#{name}_callbacks(&block) run_callbacks #{name.inspect}, &block end def self._#{name}_callbacks get_callbacks(#{name.inspect}) end def self._#{name}_callbacks=(value) set_callbacks(#{name.inspect}, value) end def _#{name}_callbacks __callbacks[#{name.inspect}] end RUBY end end ClassMethods
  12. CallbackChain DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC module ActiveSupport module Callbacks module Conditionals module

    Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods class CallbackChain #:nodoc:# include Enumerable # ... def initialize(name, config) @name = name @config = { scope: [:kind], terminator: default_terminator }.merge!(config) @chain = [] @callbacks = nil @mutex = Mutex.new end # ... end # An Array with a compile method. CallbackΠϯελϯε͕ೖΔ ഑ྻϥΠΫͳΫϥε
  13. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def define_callbacks(*names) options = names.extract_options! names.each do |name|

    name = name.to_sym set_callbacks name, CallbackChain.new(name, options) module_eval <<-RUBY, __FILE__, __LINE__ + 1 def _run_#{name}_callbacks(&block) run_callbacks #{name.inspect}, &block end def self._#{name}_callbacks get_callbacks(#{name.inspect}) end def self._#{name}_callbacks=(value) set_callbacks(#{name.inspect}, value) end def _#{name}_callbacks __callbacks[#{name.inspect}] end RUBY end end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods ClassMethods
  14. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def set_callbacks(name, callbacks) # :nodoc: self.__callbacks = __callbacks.merge(name.to_sym

    => callbacks) end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods ClassMethods
  15. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCFEDDDGBDUJPOQBDLMJCBCTUSBDU@DPOUSPMMFSDBMMCBDLTSC module AbstractController module Callbacks module ClassMethods [:before, :after,

    :around].each do |callback| define_method "#{callback}_action" do |*names, &blk| _insert_callbacks(names, blk) do |name, options| set_callback(:process_action, callback, name, options) end end # ... end end end end AbstractController
  16. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def set_callback(name, *filter_list, &block) type, filters, options =

    normalize_callback_params(filter_list, block) # ... self_chain = get_callbacks name mapped = filters.map do |filter| Callback.build(self_chain, filter, type, options) end __update_callbacks(name) do |target, chain| options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped) target.set_callbacks name, chain end end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods ClassMethods
  17. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC class Callback #:nodoc:# # ... def initialize(name,filter,kind,options,chain_config) @chain_config

    = chain_config @name = name # => :process_action @kind = kind # => :before @filter = filter # => :login_required @key = compute_identifier filter # => :login_required @if = Array(options[:if]) # => :[#<Proc:0x0000123456789012>] @unless = Array(options[:unless]) # => [] end # ... module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods Callback ίʔϧόοΫຊମ before_action :login_required, except: :destroy ͷ৔߹
  18. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def set_callback(name, *filter_list, &block) type, filters, options =

    normalize_callback_params(filter_list, block) # ... self_chain = get_callbacks name mapped = filters.map do |filter| Callback.build(self_chain, filter, type, options) end __update_callbacks(name) do |target, chain| options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped) target.set_callbacks name, chain end end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods ClassMethods
  19. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def run_callbacks(kind) callbacks = __callbacks[kind.to_sym] # ... next_sequence

    = callbacks.compile invoke_sequence = Proc.new do # ... end # Common case: no 'around' callbacks defined if next_sequence.final? # ... else invoke_sequence.call end # ... end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods Callbacks
  20. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC class CallbackChain #:nodoc:# # ... def compile @callbacks

    || @mutex.synchronize do final_sequence = CallbackSequence.new @callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback| callback.apply callback_sequence end end end # ... end # An Array with a compile method. module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods CallbackChain CallbackΠϯελϯε͕ೖΔ഑ྻΛ ࣋ͭΫϥε
  21. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC class CallbackSequence # :nodoc: def initialize( nested =

    nil, call_template = nil, user_conditions = nil ) @nested = nested @call_template = call_template @user_conditions = user_conditions @before = [] @after = [] end # ... end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods CallbackSequence ॱং௨ΓʹίʔϧόοΫΛอ؅͠ ࣮ߦ͍ͯ͘͠Ϋϥε
  22. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC class CallbackChain #:nodoc:# # ... def compile @callbacks

    || @mutex.synchronize do final_sequence = CallbackSequence.new @callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback| callback.apply callback_sequence end end end # ... end # An Array with a compile method. module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods CallbackChain CallbackΠϯελϯε͕ೖΔ഑ྻΛ ࣋ͭΫϥε
  23. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def apply(callback_sequence) user_conditions = conditions_lambdas user_callback = CallTemplate.build(@filter,

    self) case kind when :before Filters::Before.build( callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter ) when :after Filters::After.build( # before ͱಉ ) when :around callback_sequence.around( user_callback, user_conditions ) end end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods Callback ίʔϧόοΫຊମ
  24. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC class CallTemplate # :nodoc: # ... def self.build(filter,

    callback) case filter when Symbol new(nil, filter, [], nil) when String new( nil, :instance_exec, [:value], compile_lambda(filter) ) # ... end end # ... end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods CallTemplate ίʔϧόοΫΛ࣮ߦ͢Δ ProcΛ࡞ΔΫϥε
  25. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def apply(callback_sequence) user_conditions = conditions_lambdas user_callback = CallTemplate.build(@filter,

    self) case kind when :before Filters::Before.build( callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter ) when :after Filters::After.build( # before ͱಉ ) when :around callback_sequence.around( user_callback, user_conditions ) end end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods Callback ίʔϧόοΫຊମ
  26. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC module Filters # ... class Before def self.build(

    callback_sequence, user_callback, user_conditions, chain_config, filter ) halted_lambda = chain_config[:terminator] if user_conditions.any? # ... else halting( callback_sequence, user_callback, halted_lambda, filter ) end end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods Filters if, unlessΛνΣοΫ͠ඞཁͳΒ ίʔϧόοΫΛhalt͢ΔΫϥε
  27. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def self.halting( callback_sequence, user_callback, halted_lambda, filter ) callback_sequence.before

    do |env| target = env.target value = env.value halted = env.halted unless halted result_lambda = -> { user_callback.call target, value } env.halted = halted_lambda.call(target, result_lambda) if env.halted target.send :halted_callback_hook, filter end end env end end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods Filters if, unlessΛνΣοΫ͠ඞཁͳΒ ίʔϧόοΫΛhalt͢ΔΫϥε
  28. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC module ActiveSupport module Callbacks module Conditionals module Filters

    class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods def self.halting( callback_sequence, user_callback, halted_lambda, filter ) callback_sequence.before do |env| target = env.target value = env.value halted = env.halted unless halted result_lambda = -> { user_callback.call target, value } env.halted = halted_lambda.call(target, result_lambda) if env.halted target.send :halted_callback_hook, filter end end env end end def apply(callback_sequence) # ... user_callback = CallTemplate.build # ... case kind when :before Filters::Before.build( callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter ) Filters
  29. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def make_lambda lambda do |target, value, &block| target,

    block, method, *arguments = expand(target, value, block) target.send(method, *arguments, &block) end end module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods CallTemplate ίʔϧόοΫΛ࣮ߦ͢Δ ProcΛ࡞ΔΫϥε
  30. DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def expand(target, value, block) result = @arguments.map {

    |arg| case arg when :value; value when :target; target when :block; block || raise(ArgumentError) end } result.unshift @method_name result.unshift @override_block || block result.unshift @override_target || target # target, block, method, *arguments = result # target.send(method, *arguments, &block) result end ϦΫΤετΛड͚ͨίϯτϩʔϥ before_actionͰొ࿥ͨ͠
 Πϯελϯεϝιου module ActiveSupport module Callbacks module Conditionals module Filters class Callback class CallTemplate class CallbackSequence class CallbackChain module ClassMethods CallTemplate ίʔϧόοΫΛ࣮ߦ͢Δ ProcΛ࡞ΔΫϥε AwesomeController.new.send(:login_required) ͱҰॹʂʂ
  31. औΕͨ class AwesomeController < ApplicationController def index p self.__callbacks[:process_action].class #

    => ActiveSupport::Callbacks::CallbackChain p self.__callbacks[:process_action].send(:chain).first # => #<ActiveSupport::Callbacks::Callback:0x0000123456789001 # @chain_config= # {:scope=>[:kind], # :terminator=>#<Proc:0x0000123456789012>, # :skip_after_callbacks_if_terminated=>true}, # @filter=:require_login, # @if=[#<Proc:0x0000123456789012>], # @key=:require_login, # @kind=:before, # @name=:process_action, # @unless=[]> end end
  32. AbstractController::Callbacks module AbstractController module Callbacks # ... def process_action(*args) run_callbacks(:process_action)

    do super end end end end ϞϯΩʔύονͰ͜ͷݺͼग़͠ޙʹ ͍͍ײ͡ʹॻ͖ग़ͯ͋͛ͨ͠ΒΑͦ͞͏
  33. ϞϯΩʔύον module ActionTracer module MonkeyPatches module AbstractController module Callbacks def

    process_action(*args) ActionTracer.log(self) do super end end end end end end AbstractController::Callbacks#process_action ΛΦʔόʔϥΠυ
  34. ͍͍ײ͡ʹॻ͖ग़͢ module ActionTracer class << self def log(controller) result =

    yield Filters.build(controller).print result end end end
  35. ͍͍ײ͡ʹॻ͖ग़͢ class ActionTracer::Filters def self.build(controller) # ... raw_filters = controller.__callbacks[:process_action].send(:chain)

    raw_filters.group_by(&:kind).each do |kind, filter| filters[kind] = filter.map(&:raw_filter).map do |f| Filter.new(f, method: f.is_a?(Symbol) ? controller.method(f) : f) end end # ... end def print (@before + @around).map(&:to_a).each do |filter| ActionTracer.logger.info filter end # ... end end
  36. ActiveSupport::Callbacks DBMMCBDLTSCcSBJMTSBJMT IUUQTHJUIVCDPNSBJMTSBJMTCMPCDBBDUJWFTVQQPSUMJCBDUJWF@TVQQPSUDBMMCBDLTSC def expand(target, value, block) result = @arguments.map

    { |arg| case arg when :value; value when :target; target when :block; block || raise(ArgumentError) end } result.unshift @method_name result.unshift @override_block || block result.unshift @override_target || target # target, block, method, *arguments = result # target.send(method, *arguments, &block) result end expand ͕ݺ͹ΕΔͷ͸ ࣮ࡍʹ࣮ߦ͞ΕΔίʔϧόοΫ͚ͩ
  37. module ActionTracer def self.filter_collector @filter_collector ||= TracePoint.new(:return) do |tp| #

    NOTE: ActiveSupport::Callbacks::CallTemplate is a private class if tp.method_id == :expand && tp.defined_class == ActiveSupport::Callbacks::CallTemplate if tp.return_value&.first.is_a? ActionController::Base case tp.return_value[2] # ... when Symbol # filter is a method applied_filters << tp.return_value[2] end end end end end def self.applied_filters @applied_filters ||= [] end end BDUJPO@USBDFSSCcNBLJDBNFMBDUJPO@USBDFS IUUQTHJUIVCDPNNBLJDBNFMBDUJPO@USBDFSCMPCGMJCBDUJPO@USBDFSBDUJPO@USBDFSSC
  38.  ग़ྗͰ͖ͨ I, [2020-09-27T03:25:43.018298 #1] INFO -- : [“APPLIED",:set_turbolinks_location_header_from _session,

    “/usr/local/bundle/gems/turbolinks-redirection.rb”, 43] I, [2020-09-27T03:25:43.019410 #1] INFO -- : ["APPLIED", :verify_authenticity_token, “/usr/local/bundle/gems/actionpack-…/request_forgery_protection.rb”, 211] I, [2020-09-27T03:25:43.021131 #1] INFO -- : ["APPLIED", :require_login, “/myapp/app/controllers/awesome_controller.rb", 17] I, [2020-09-27T03:25:43.022063 #1] INFO -- : ["NO_APPLIED", :set_awesome, “/myapp/app/controllers/awesome_controller.rb", 25] I, [2020-09-27T03:25:43.023716 #1] INFO -- : ["APPLIED", :with_readonly, “/myapp/app/controllers/awesome_controller.rb", 21] I, [2020-09-27T03:25:43.025547 #1] INFO -- : ["ACTION", :index, “/myapp/app/controllers/awesome_controller.rb", 7] I, [2020-09-27T03:25:43.026297 #1] INFO -- : ["APPLIED", :with_readonly, “/myapp/app/controllers/awesome_controller.rb", 21] I, [2020-09-27T03:25:43.027203 #1] INFO -- : ["APPLIED", :store_location, “/myapp/app/controllers/awesome_controller.rb", 27] I, [2020-09-27T03:25:43.030074 #1] INFO -- : ["APPLIED", :verify_same_origin_request, “/usr/local/bundle/gems/actionpack-…/request_forgery_protection.rb”, 240]
  39. •ΞϓϦ͕஗͍ •CI ͕஗͍ •ϦϦʔε࡞ۀ͕஗͍ •։ൃ଎౓͕஗͍ •ίʔυ͕ಡΈʹ͍͘ •ίʔυ͕Ԛ͍ •etc etc… ʮݱ৔ͷࠓ͋Δ՝୊ʯ

    ෆద੾ͳΤϥʔϋϯυϦϯά ଐਓԽ͍ͯ͠ΔΤϥʔ؂ࢹ ແବͳSQLͷൃߦ ίʔσΟϯάϧʔϧ͕গͳ͍ ແடংͳϝλϓϩ େྔͷσουίʔυ ࢖ΘΕ͍ͯͳ͍ΞΫγϣϯ େྔͷApplicationController ਖ਼نԽ͞Ε͍ͯͳ͍ςʔϒϧ ൿ఻ͷλϨscope ௒ઈFatModel γεςϜεϖοΫ͕গͳ͍ ແବͳςετσʔλͷ࡞੒ ΦϨΦϨϙϦϞʔϑΟοΫςʔϒϧ ߦ͖ա͗ͨڞ௨Խ