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

Patterns of Pluggable Gems (ConFoo 2014)

Patterns of Pluggable Gems (ConFoo 2014)

One strength of the Ruby community is the simplicity of sharing code via gems. Popular gems even develop their own ecosystem of plugins around them.

But extending a gem that wasn't built with flexibility in mind isn't easy. This talk covers the highs and lows of interacting with other gems. We'll cover how to make your gem easy to plug into, from patterns and events, to configuration and documentation.

Jason R Clark

February 26, 2014
Tweet

More Decks by Jason R Clark

Other Decks in Technology

Transcript

  1. newrelic_rpm module NewRelic::Agent::BrowserMonitoring def browser_monitoring_queue_time queue_time = current_transaction.queue_time millis =

    queue_time.to_f * 1000.0 clamp_to_positive(millis.round) end def footer_js_string(config) "<script>...#{browser_monitoring_queue_time}" end end Wednesday, February 26, 14
  2. Where We're Going • Pass It On • Events •

    Middleware • Lifecycle • Names and Paths • Config • Docs Wednesday, February 26, 14
  3. excon class SimpleInstrumentor class << self def instrument(name, params =

    {}, &blk) puts "#{name} just happened." yield if block_given? end end end Wednesday, February 26, 14
  4. Resque class SendMessageJob def self.perform(id, text) user = User.find(id) user.send_message(text)

    end end Resque.enqueue(SendMessageJob, 42, "Yo") Wednesday, February 26, 14
  5. Where We've Been • Pass It On • Events •

    Middleware • Lifecycle • Names and Paths • Config • Docs Wednesday, February 26, 14
  6. Where We've Been • Pass It On • Events •

    Middleware • Lifecycle • Names and Paths • Config • Docs Wednesday, February 26, 14
  7. # [status, headers, response] def call(env) # ... before result

    = @app.call(env) # ... after result end Wednesday, February 26, 14
  8. # [status, headers, response] def call(env) # ... before result

    = @app.call(env) # ... after result end Wednesday, February 26, 14
  9. http://flic.kr/p/SSGmF ActionDispatch::Static Rack::Lock <ActiveSupport::Cache::Strategy> Rack::Runtime Rack::MethodOverride ActionDispatch::RequestId Rails::Rack::Logger ActionDispatch::ShowExceptions ActionDispatch::DebugExceptions

    ActionDispatch::RemoteIp ActionDispatch::Reloader ActionDispatch::Callbacks ActiveRecord::ConnectionAdapters ActiveRecord::QueryCache ActionDispatch::Cookies ActionDispatch::Session::CookieStore ActionDispatch::Flash ActionDispatch::ParamsParser Rack::Head Rack::ConditionalGet Rack::ETag AgentSnoop::Middleware RpmTestApp::Application.routes Wednesday, February 26, 14
  10. # [status, headers, response] def call(env) # ... before result

    = @app.call(env) # ... after result end Wednesday, February 26, 14
  11. class MyMiddleware def initialize(options={}) # options == { :foo =>

    1 } end def call(worker, msg, queue) yield end end Wednesday, February 26, 14
  12. Where We've Been • Pass It On • Events •

    Middleware • Lifecycle • Names and Paths • Config • Docs Wednesday, February 26, 14
  13. loads gems forks after_fork starts loop forks after_fork starts loop

    loads gems preload_app true preload_app false unicorn Wednesday, February 26, 14
  14. loads gems forks after_fork starts loop forks after_fork starts loop

    loads gems preload_app true preload_app false unicorn Wednesday, February 26, 14
  15. loads gems forks after_fork starts loop forks after_fork starts loop

    loads gems preload_app true preload_app false unicorn Wednesday, February 26, 14
  16. Where We've Been • Pass It On • Events •

    Middleware • Lifecycle • Names and Paths • Config • Docs Wednesday, February 26, 14
  17. ~/source/newrelic/ruby_agent/lib: ls -la drwxr-xr-x Sep 19 14:46 . drwxr-xr-x Oct

    10 11:19 .. drwxr-xr-x Oct 10 11:20 new_relic -rw-r--r-- Sep 19 14:46 newrelic_rpm.rb drwxr-xr-x Sep 19 14:46 sequel drwxr-xr-x Oct 7 08:53 tasks Wednesday, February 26, 14
  18. ~/source/newrelic/ruby_agent/lib: ls -la drwxr-xr-x Sep 19 14:46 . drwxr-xr-x Oct

    10 11:19 .. drwxr-xr-x Oct 10 11:20 new_relic -rw-r--r-- Sep 19 14:46 newrelic_rpm.rb drwxr-xr-x Sep 19 14:46 sequel drwxr-xr-x Oct 7 08:53 tasks Wednesday, February 26, 14
  19. newrelic_rpm module NewRelic module Agent class AgentLogger LOG_LEVELS = {

    "debug" => Logger::DEBUG, ... } end end end Wednesday, February 26, 14
  20. newrelic_rpm module NewRelic module Agent class AgentLogger LOG_LEVELS = {

    "debug" => Logger::DEBUG, ... } end end end Wednesday, February 26, 14
  21. newrelic_rpm module NewRelic module Agent class AgentLogger LOG_LEVELS = {

    "debug" => ::Logger::DEBUG, ... } end end end Wednesday, February 26, 14
  22. Where We've Been • Pass It On • Events •

    Middleware • Lifecycle • Names and Paths • Config • Docs Wednesday, February 26, 14
  23. yml + ERB file = File.read("./config/awesome_gem.yml") # Locals available in

    ERB default_awesome_key = "YEAH!" erb = ERB.new(file).result(binding) config = YAML.load(erb) Wednesday, February 26, 14
  24. unicorn worker_processes 5 preload_app true timeout 30 after_fork do |server,

    worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end Wednesday, February 26, 14
  25. Where We've Been • Pass It On • Events •

    Middleware • Lifecycle • Names and Paths • Config • Docs Wednesday, February 26, 14
  26. Where We've Been • Pass It On • Events •

    Middleware • Lifecycle • Names and Paths • Config • Docs Wednesday, February 26, 14
  27. Where We've Been • Pass It On • Events •

    Middleware • Lifecycle • Names and Paths • Config • Docs Wednesday, February 26, 14
  28. Where We've Been • Pass It On • Events •

    Middleware • Lifecycle • Names and Paths • Config • Docs Jason Clark @jasonrclark Ruby Agent Engineer Wednesday, February 26, 14