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

Building Extractable Libraries in Rail - Railsconf

Building Extractable Libraries in Rail - Railsconf

Build better libraries in Rails! Talk given at Railsconf 2013

Patrick Robertson

April 30, 2013
Tweet

More Decks by Patrick Robertson

Other Decks in Programming

Transcript

  1. In order to ship more code I believe it can

    benefit from some conventions
  2. # lib/twitter_user.rb class TwitterUser def initialize(user) @user = user end

    end # lib/twitter_profile.rb class TwitterProfile def initialize(twitter_user, image_url) @user = twitter_user @image_url = image_url end end
  3. Rails 3 brought a wonderful convention for removing /lib from

    automatically being loaded on application boot...
  4. ... however our first instinct is to do this: #

    config/application.rb # Custom directories with classes and modules you want to be autoloadable. config.autoload_paths += %W(#{config.root}/lib) Let’s try something different!
  5. We have created a namespace and setup a proper layout

    when we need to extract our code outside the application into a gem. ... in ten seconds or less :)
  6. It’s so simple to do this: # lib/twitter_wrangler.rb module TwitterWrangler

    OAUTH_KEY = ‘ABCDEFG1234ZXYZB2324’ end Or even this: # lib/twitter_wrangler.rb module TwitterWrangler OAUTH_KEY = ENV[‘TWITTER_KEY’] end
  7. But we already have an entry point for our library

    code. So let’s exploit the heck out of it!
  8. # lib/twitter_wrangler/configuration.rb module TwitterWrangler class Configuration < Struct.new(:oauth_key) end class

    << self attr_accessor :configuration end def self.configure self.configuration ||= Configuration.new yield(configuration) if block_given? end end
  9. # lib/twitter_wrangler/configuration.rb module TwitterWrangler class Configuration < Struct.new(:oauth_key) end class

    << self attr_accessor :configuration end def self.configure self.configuration ||= Configuration.new yield(configuration) if block_given? end end
  10. # lib/twitter_wrangler/configuration.rb module TwitterWrangler class Configuration < Struct.new(:oauth_key) end class

    << self attr_accessor :configuration end def self.configure self.configuration ||= Configuration.new yield(configuration) if block_given? end end
  11. # lib/twitter_wrangler/configuration.rb module TwitterWrangler class Configuration < Struct.new(:oauth_key) end class

    << self attr_accessor :configuration end def self.configure self.configuration ||= Configuration.new yield(configuration) if block_given? end end
  12. # lib/twitter_wrangler/configuration.rb module TwitterWrangler class Configuration < Struct.new(:oauth_key) end class

    << self attr_accessor :configuration end def self.configure self.configuration ||= Configuration.new yield(configuration) if block_given? end end
  13. # lib/twitter_wrangler/tweeting_patient.rb module TwitterWrangler::TweetingPatient def bmi_twitter_message “Today my BMI is

    #{body_mass_index} and I’m #{percent_of_body_mass_index_goal} from my goal of #{body_mass_index_goal}!” end end
  14. # spec/twitter_wrangler/tweeting_patient_spec.rb describe TweetingPatient do let(:patient) { FakePatient.new } before

    { patient.extend TweetingPatient } describe ‘#bmi_twitter_message’ do let(:tweet) { patient.bmi_twitter_message } it ‘crafts a lovely tweet’ do expect(tweet).to include ‘Today my BMI is...’ end end end
  15. # spec/twitter_wrangler/tweeting_patient_spec.rb describe TweetingPatient do let(:patient) { FakePatient.new } before

    { patient.extend TweetingPatient } describe ‘#bmi_twitter_message’ do let(:tweet) { patient.bmi_twitter_message } it ‘crafts a lovely tweet’ do expect(tweet).to include ‘Today my BMI is...’ end end end
  16. # spec/twitter_wrangler/tweeting_patient_spec.rb describe TweetingPatient do let(:patient) { FakePatient.new } before

    { patient.extend TweetingPatient } describe ‘#bmi_twitter_message’ do let(:tweet) { patient.bmi_twitter_message } it ‘crafts a lovely tweet’ do expect(tweet).to include ‘Today my BMI is...’ end end end
  17. # spec/twitter_wrangler/tweeting_patient_spec.rb describe TweetingPatient do let(:patient) { FakePatient.new } before

    { patient.extend TweetingPatient } describe ‘#bmi_twitter_message’ do let(:tweet) { patient.bmi_twitter_message } it ‘crafts a lovely tweet’ do expect(tweet).to include ‘Today my BMI is...’ end end end
  18. # lib/twitter_wrangler/bmi_twitter_update.rb module TwitterWrangler class BMITwitterUpdate < Struct.new(:patient) def call

    Queue.push tweeting_patient.bmi_twitter_message end private def tweeting_patient @tweeting_patient ||= patient.extend TweetingPatient end end end
  19. # lib/twitter_wrangler/bmi_twitter_update.rb module TwitterWrangler class BMITwitterUpdate < Struct.new(:patient) def call

    Queue.push tweeting_patient.bmi_twitter_message end private def tweeting_patient @tweeting_patient ||= patient.extend TweetingPatient end end end
  20. # lib/twitter_wrangler/bmi_twitter_update.rb module TwitterWrangler class BMITwitterUpdate < Struct.new(:patient) def call

    Queue.push tweeting_patient.bmi_twitter_message end private def tweeting_patient @tweeting_patient ||= patient.extend TweetingPatient end end end
  21. # lib/twitter_wrangler/bmi_twitter_update.rb module TwitterWrangler class BMITwitterUpdate < Struct.new(:patient) def call

    Queue.push tweeting_patient.bmi_twitter_message end private def tweeting_patient @tweeting_patient ||= patient.extend TweetingPatient end end end
  22. # lib/twitter_wrangler/bmi_twitter_update.rb module TwitterWrangler class BMITwitterUpdate < Struct.new(:patient) def call

    Queue.push tweeting_patient.bmi_twitter_message end private def tweeting_patient @tweeting_patient ||= patient.extend TweetingPatient end end end
  23. # spec/twitter_wrangler/bmi_twitter_update_spec.rb describe BMITwitterUpdate do describe ‘#call’ do let(:patient) {

    mock() } let(:update) { BMITwitterUpdate.new(patient) } before { Queue.stubs(:push) } it ‘extends TweetingPatient’ do update.call expect(patient).to have_received(:extend).with TweetingPatient end it ‘queues the twitter message’ do update.call expect(Queue).to have_received(:push).with patient.bmi_twitter_message end end end
  24. # spec/twitter_wrangler/bmi_twitter_update_spec.rb describe BMITwitterUpdate do describe ‘#call’ do let(:patient) {

    mock() } let(:update) { BMITwitterUpdate.new(patient) } before { Queue.stubs(:push) } it ‘extends TweetingPatient’ do update.call expect(patient).to have_received(:extend).with TweetingPatient end it ‘queues the twitter message’ do update.call expect(Queue).to have_received(:push).with patient.bmi_twitter_message end end end
  25. # spec/twitter_wrangler/bmi_twitter_update_spec.rb describe BMITwitterUpdate do describe ‘#call’ do let(:patient) {

    mock() } let(:update) { BMITwitterUpdate.new(patient) } before { Queue.stubs(:push) } it ‘extends TweetingPatient’ do update.call expect(patient).to have_received(:extend).with TweetingPatient end it ‘queues the twitter message’ do update.call expect(Queue).to have_received(:push).with patient.bmi_twitter_message end end end
  26. # spec/twitter_wrangler/bmi_twitter_update_spec.rb describe BMITwitterUpdate do describe ‘#call’ do let(:patient) {

    mock() } let(:update) { BMITwitterUpdate.new(patient) } before { Queue.stubs(:push) } it ‘extends TweetingPatient’ do update.call expect(patient).to have_received(:extend).with TweetingPatient end it ‘queues the twitter message’ do update.call expect(Queue).to have_received(:push).with patient.bmi_twitter_message end end end
  27. # spec/twitter_wrangler/bmi_twitter_update_spec.rb describe BMITwitterUpdate do describe ‘#call’ do let(:patient) {

    mock() } let(:update) { BMITwitterUpdate.new(patient) } before { Queue.stubs(:push) } it ‘extends TweetingPatient’ do update.call expect(patient).to have_received(:extend).with TweetingPatient end it ‘queues the twitter message’ do update.call expect(Queue).to have_received(:push).with patient.bmi_twitter_message end end end
  28. # spec/twitter_wrangler/bmi_twitter_update_spec.rb describe BMITwitterUpdate do describe ‘#call’ do let(:patient) {

    mock() } let(:update) { BMITwitterUpdate.new(patient) } before { Queue.stubs(:push) } it ‘extends TweetingPatient’ do update.call expect(patient).to have_received(:extend).with TweetingPatient end it ‘queues the twitter message’ do update.call expect(Queue).to have_received(:push).with patient.bmi_twitter_message end end end
  29. # app/controllers/bmi_controller.rb class BmiController < ApplicationController def create bmi =

    patient.bmis.create(:bmi) Resque.enqueue :bmi_twitter_update_job, patient.id respond_with bmi end private def patient @patient ||= current_user.patients.find(:patient_id) end end