RubyTapas #179 - #183
179 Sequel
★★
- PostgreSQL, MySQL, Oracle, and many others
require "sequel" DB = Sequel.sqlite DB.create_table :people do primary_key :id String :name end DB.create_table :items do foreign_key :person_id, :people String :name Integer :quantity, default: 1 unique [:person_id, :name] end
stacey_id = DB[:people].insert(name: "Stacey") DB[:people].count DB[:people].all DB[:items].each do |row| p row end DB[:items].first DB[:items].sum(:quantity) DB[:items].where(name: "Mineral Water") # => #<Sequel::SQLite::Dataset: "SELECT * FROM `items` WHERE (`name` = 'Mineral Water')">
- If we replace #join with #graph, Sequel automatically aliases the items_name column in order to resolve the naming collision
DB[:people].join(:items, person_id: :id).where(person_id: avdi_id).all # => [{:id=>2, :name=>"Granola", :person_id=>2, :quantity=>1}, DB[:people].graph(:items, person_id: :id).where(person_id: avdi_id).all # => [{:id=>2, :name=>"Avdi", :person_id=>2, :items_name=>"Granola", :quantity=>1},
180 Ghost Load
★★
- ghost_episode.rb (ghost object pattern)
- def initialize(attributes={})
- @load_state = :ghost
- def load
- return if load_state == :loaded
- def description
- load
- @description
- def initialize(attributes={})
ep.load_state # => :ghost ep.description # => "Today we explore a pattern for bridging the gap between different domain models." ep.load_state # => :loaded
181 Schwartzian Transform
★★
videos = Dir["../*/[0-9][0-9][0-9]*.mp4"] def duration(filename) stats = `avprobe #{filename} 2>&1` /(?<=Duration: )\d\d:\d\d:\d\d\.\d\d/.match(stats).to_s end
duration(videos.last) # => "00:04:44.48" videos.count # => 144 start_time = Time.now sorted_videos = videos.sort{|x, y| duration(x) <=> duration(y)} Time.now - start_time # => 53.290444705
problem of slow sorting
- create a global $call_count variable. inside duration
- we're sorting 144 video files. But the #duration method is called a whopping 1824 times!
Let's rewrite our sort. Before the sort, we map our list of videos into a list of two-element arrays. Each array has the video file name as its first element, and the video duration as the second element.
sorted_videos = videos.map{|v| [v, duration(v)]} .sort{|(xv, xd), (yv, yd)| xd <=> yd} .map(&:first) Time.now - start_time # => 4.059575059
sort_byと同じ
sorted_videos = videos.sort_by{|v| duration(v)}
182 Macro
★★
episode 180 続き
class Episode def self.lazy_accessor(*names) names.each do |name| attr_writer name define_method(name) do load instance_variable_get("@#{name}") end end end lazy_accessor :description, :synopsis, :publish_time
183 Extracting Ghost Load
episode 180, 182 続き
★★
- module Ghostly追加
- def lazy_accessor定義
- module Macros追加して内容を移動 + private化
- def self.included
- load_state, load
module RubyTapas module Ghostly module Macros private def lazy_accessor(*names) names.each do |name| attr_writer name define_method(name) do load instance_variable_get("@#{name}") end end end end def self.included(other) other.extend(Macros) end attr_accessor :data_source attr_writer :load_state def load_state @load_state ||= :ghost end def load return if load_state == :loaded data_source.load(self) end end class Episode include Ghostly