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

Don't Repeat Yourself, Repeat Others

Don't Repeat Yourself, Repeat Others

Avatar for John Nunemaker

John Nunemaker

December 30, 2010
Tweet

More Decks by John Nunemaker

Other Decks in Programming

Transcript

  1. Why? I am obsessed with improving I have learned a

    lot of late I love sharing what I learn
  2. “ Jason Sage Reinventing the wheel is as important to

    a developer’s education and skill as weightlifting is to a body builder. 97 Things Every Programmer Should Know
  3. “ John Nunemaker The lessons learned and deeper appreciation for

    ActiveRecord and DataMapper alone was enough to make it worth it. RailsTips.org Comment
  4. # person.rb class Person; end # some_other_ruby_file.rb autoload Person, 'path/to/person'

    # as soon as Person class is used, # ruby requires the file person = Person.new # if it is not used, it is not required
  5. module MongoMapper autoload :Document, 'mongo_mapper/document' autoload :EmbeddedDocument, 'mongo_mapper/embedded_document' autoload :Plugins,

    'mongo_mapper/plugins' autoload :Version, 'mongo_mapper/version' module Plugins autoload :Associations, 'mongo_mapper/plugins/associations' autoload :Callbacks, 'mongo_mapper/plugins/callbacks' autoload :Clone, 'mongo_mapper/plugins/clone' autoload :Descendants, 'mongo_mapper/plugins/descendants' autoload :Dirty, 'mongo_mapper/plugins/dirty' end end
  6. def method_missing(method, *args, &block) if method.to_s =~ /(_changed\?|_change|_will_change!|_was)$/ method_suffix =

    $1 key = method.to_s.gsub(method_suffix, '') if key_names.include?(key) case method_suffix when '_changed?' key_changed?(key) when '_change' key_change(key) when '_will_change!' key_will_change!(key) when '_was' key_was(key) end else super end else super end end
  7. module MongoMapper module Document def self.included(model) model.class_eval do extend Plugins

    plugin Plugins::Associations plugin Plugins::Equality plugin Plugins::Inspect # etc... end end end end
  8. class Activity include MongoMapper::Document key :source, Hash key :source_type, String

    key :action, String timestamps! end class Article include MongoMapper::Document key :title, String end
  9. article = Article.create(:title => 'Yo Dawg') activity = Activity.create({ :source

    => article.to_mongo, :source_type => 'Article', :action => 'create' })
  10. class Activity include MongoMapper::Document key :source, Hash key :source_type, String

    key :action, String timestamps! def source=(value) self.source_type = value.class.name super value.to_mongo end end
  11. class Activity module MongoMapperKeys def source read_key :source end def

    source=(value) write_key :source, value end def source? read_key(:source).present? end end include MongoMapperKeys end
  12. def create_accessors_for(key) accessors_module.module_eval <<-end_eval def #{key.name} read_key(:#{key.name}) end def #{key.name}_before_typecast

    read_key_before_typecast(:#{key.name}) end def #{key.name}=(value) write_key(:#{key.name}, value) end def #{key.name}? read_key(:#{key.name}).present? end end_eval include accessors_module end
  13. class Person attr_accessor :name def initialize(name) @name = name end

    end puts Person.new('John') == Person.new('John') # false puts Person.new('John').eql?(Person.new('John')) # false
  14. class Person attr_accessor :name def initialize(name) @name = name end

    def eql?(other) self.class.eql?(other.class) && name == other.name end end puts Person.new('John') == Person.new('John') # false puts Person.new('John').eql?(Person.new('John')) # true
  15. class Person attr_accessor :name def initialize(name) @name = name end

    def eql?(other) self.class.eql?(other.class) && name == other.name end alias :== :eql? end puts Person.new('John') == Person.new('John') # true puts Person.new('John').eql?(Person.new('John')) # true
  16. class OptionsHash attr_reader :source def initialize(source) @source = source end

    def [](key) @source[key] end def []=(key, value) @source[key] = value end end
  17. hash1 = OptionsHash.new({:foo => 'bar'}) hash2 = hash1.clone puts hash1[:foo]

    # 'bar' hash2[:foo] = 'surprise' puts hash1[:foo] # 'surprise' puts hash1.source.equal?(hash2.source) # true
  18. class OptionsHash def initialize_copy(other) super @source = @source.clone end end

    hash1 = OptionsHash.new({:foo => 'bar'}) hash2 = hash1.clone puts hash1[:foo] # 'bar' hash2[:foo] = 'surprise' puts hash1[:foo] # 'bar' puts hash1.source.equal?(hash2.source) # false
  19. module MongoMapper module Plugins module Sci module ClassMethods def inherited(subclass)

    key :_type, String unless key?(:_type) unless subclass.embeddable? subclass.set_collection_name(collection_name) end super end end end end end
  20. module MongoMapper module Document def self.included(model) model.class_eval do extend Plugins

    plugin Plugins::Associations plugin Plugins::Equality plugin Plugins::Inspect # etc... end end end end
  21. class Proxy def initialize(source) @source = source end private def

    method_missing(method, *args, &block) @source.send(method, *args, &block) end end
  22. class Proxy def initialize(source) @source = source end private def

    method_missing(method, *args, &block) @source.send(method, *args, &block) end end results = [1, 2, 3, 4] proxy = Proxy.new(results) puts proxy.size # 4 puts results.size # 4 puts proxy[2] # 3 puts results[2] # 3
  23. query = Plucky::Query.new(collection) docs = query.paginate(:per_page => 1) puts docs.class

    # Array puts docs.total_entries # 2 puts docs.total_pages # 2 puts docs.current_page # 1 puts [].total_pages # NoMethodError!
  24. module Pagination def total_entries 50 end def total_pages 5 end

    end result = [1, 2, 3, 4] result.extend(Pagination) puts result.total_entries # 50 puts result.total_pages # 5
  25. module Plucky class Query def paginate(opts={}) # some stuff paginator

    = Pagination::Paginator.new(total, page, limit) query[:limit] = paginator.limit query[:skip] = paginator.skip query.all.tap do |docs| docs.extend(Pagination::Decorator) docs.paginator(paginator) end end end end
  26. require 'forwardable' module Plucky module Pagination module Decorator extend Forwardable

    def_delegators :@paginator, :total_entries, :total_pages, :current_page, :per_page, :previous_page, :next_page, :skip, :limit, :offset, :out_of_bounds? def paginator(p=nil) return @paginator if p.nil? @paginator = p self end end end end
  27. Powered by Plugins MongoMapper is associations, callbacks, clone, descendants, dirty,

    equality, identity_map, inspect, keys, logger, modifiers, pagination, persistence, protected, rails, serialization, timestamps, userstamps, validations
  28. module MongoMapper module Plugins def plugins @plugins ||= [] end

    def plugin(mod) extend mod::ClassMethods if mod.const_defined?(:ClassMethods) include mod::InstanceMethods if mod.const_defined?(:InstanceMethods) mod.configure(self) if mod.respond_to?(:configure) plugins << mod end end end
  29. module MongoMapper module Document def self.included(model) model.class_eval do extend Plugins

    plugin Plugins::Document plugin Plugins::Associations plugin Plugins::Clone plugin Plugins::Equality plugin Plugins::Indexes plugin Plugins::Keys # etc end super end end end
  30. module ActsAsListFu module ClassMethods def reorder(ids) # reorder ids... end

    end module InstanceMethods def move_to_top # move to top end end def self.configure(model) model.key :position, Integer, :default => 1 end end
  31. “ Mike Taylor I want to make things, not just

    glue things together. Whatever Happened to Programming
  32. module Scrobbler module REST class Connection def initialize(base_url, args =

    {}) @base_url = base_url @username = args[:username] @password = args[:password] end def get(resource, args = nil) request(resource, "get", args) end def post(resource, args = nil) request(resource, "post", args) end # removed to shorten... end end end
  33. class Status include HappyMapper element :id, Integer element :text, String

    element :created_at, Time element :source, String element :truncated, Boolean element :in_reply_to_status_id, Integer element :in_reply_to_user_id, Integer element :favorited, Boolean has_one :user, User end
  34. class Account def add_user(user) user = user.is_a?(User) ? user :

    User.find(user) self.memberships << user.id end end