One project, 3 gems

27
One project, three gems Mike Williams Cogent Consulting in association with

description

Three handy Ruby gems inspired by the same project at Lonely Planet.

Transcript of One project, 3 gems

Page 1: One project, 3 gems

One project,three gems

Mike WilliamsCogent Consulting

in association with

Page 2: One project, 3 gems

Architecture

<stuff/>“Atlas”

Page 3: One project, 3 gems

WORLD

Australia

Pacific

Victoria

Europe

Africa

Asia

Americas

New Zealand

NSW

MelbourneSydney

WA

Geelong

Growing Treesarboreal

(hotel)

(restaurant)

(sight)

Page 4: One project, 3 gems

WORLD

Australia

Pacific

Victoria

Europe

Africa

Asia

Americas

New Zealand

NSW

MelbourneSydney

WA

Geelong

arboreal

how do I select this?

Page 5: One project, 3 gems

Path Enumeration

@victoria = Place.find_by_name(“Victoria”)@victoria.ancestry_string#=> “-4-14-15-”

WORLD

Australia

Pacific

Victoria

Europe

Africa

Asia

Americas

New Zealand

NSW

MelbourneSydney

WA

Geelong

4

14

15

arboreal

Page 6: One project, 3 gems

@victoria.ancestorsSELECT * FROM places WHERE (id in (4,14,15))

WORLD

Australia

Pacific

Victoria

Europe

Africa

Asia

Americas

New Zealand

NSW

MelbourneSydney

WA

Geelong

4

14

15

arboreal

Page 7: One project, 3 gems

@australia = Place.find_by_name(“Australia”)

@australia.childrenSELECT * FROM places WHERE (places.parent_id = 15)

WORLD

Australia

Pacific

Victoria

Europe

Africa

Asia

Americas

New Zealand

NSW

MelbourneSydney

WA

Geelong

15

arboreal

Page 8: One project, 3 gems

@australia.descendantsSELECT * FROM places WHERE (places.ancestry_string like ‘-4-14-15-%’)

WORLD

Australia

Pacific

Europe

Africa

Asia

Americas

New Zealand

MelbourneSydney

WA

Geelong

“-4-14-15-”

“-4-14-15-16-”

“-4-14-15-22-”

Victoria NSW

arboreal

Page 9: One project, 3 gems

@australia.subtreeSELECT * FROM places WHERE (places.id = 15 OR places.ancestry_string like ‘-4-14-15-%’)

WORLD

Australia

Pacific

Europe

Africa

Asia

Americas

New Zealand

MelbourneSydney

WA

Geelong

“-4-14-15-”

“-4-14-15-16-”

“-4-14-15-22-”

Victoria NSW

arboreal

15

Page 10: One project, 3 gems

@australia.subtree.scope(:find, :conditions)#=> [“places.id = ? OR places.ancestry_string like ?”, 15, “-4-14-15-%”]

class Place def contained_pois Poi.scoped(:include => :place, :conditions => subtree.scope(:find, :conditions)) endend

@australia.contained_poisSELECT ... FROM pois LEFT OUTER JOIN places ON places.id = pois.place_id WHERE (places.id = 15 OR places.ancestry_string like ‘-4-14-15-%’)

arboreal

Page 11: One project, 3 gems

WORLD

Australia

Pacific

Victoria

Europe

Africa

Asia

Americas

New Zealand

NSW

MelbourneSydney

WA

Geelong

@australia.contained_poisSELECT ... FROM pois LEFT OUTER JOIN places ON places.id = pois.place_id WHERE (places.id = 15 OR places.ancestry_string like ‘-4-14-15-%’)

arboreal

Page 12: One project, 3 gems

<pois/>“Atlas”

GET http://stuff.local/places/15/pois

Page 13: One project, 3 gems

<pois type="array"> <poi> <created-at type="datetime">2010-08-25T23:35:59Z</created-at> <email nil="true"></email> <id type="integer">6</id> <latitude type="decimal">-37.8002389992226</latitude> <longitude type="decimal">144.901535511017</longitude> <name>Footscray Market</name> <place-id type="integer">26</place-id> <review>A frenetic covered food market.</review> <type>See</type> <updated-at type="datetime">2010-08-25T23:35:59Z</updated-at> <url nil="true"></url> </poi> <poi> <created-at type="datetime">2010-08-25T23:35:59Z</created-at> <email nil="true"></email> <id type="integer">7</id> <latitude type="decimal">-37.8020224141169</latitude> <longitude type="decimal">144.983611106873</longitude> <name>Panama Dining Room</name> <place-id type="integer">26</place-id> <review>Franco-Fitzroy pub grub and ersatz Manhattan views.</review> <type>Eat</type> <updated-at type="datetime">2010-08-25T23:35:59Z</updated-at> <url nil="true"></url> </poi> ...

Page 14: One project, 3 gems

<pois type="array"> <poi href="http://stuff.local/pois/6"> <name>Footscray Market</name> <type>See</type> <review>A frenetic covered food market.</review> <place href="http://stuff.local/places/26"> <name>Melbourne</name> </place> </poi> <poi href="http://stuff.local/pois/7"> <name>Panama Dining Room</name> <type>Eat</type> <review>Franco-Fitzroy pub grub and ersatz Manhattan views.</review> <place href="http://stuff.local/places/26"> <name>Melbourne</name> </place> </poi> <poi href="http://stuff.local/pois/8"> <name>Sydney Opera House</name> <type>See</type> <review/> <place href="http://stuff.local/places/17"> <name>Sydney</name> </place> </poi></pois>

Page 15: One project, 3 gems

# BEFORE ...xml.pois :type => “array” do @pois.each do |poi| xml.poi :href => poi_url(poi) do xml.name(poi.name) xml.type(poi.type) xml.review(poi.review) xml.place :href => place_url(poi.place) do xml.name poi.place.name end end endend

Page 16: One project, 3 gems

# BEFORE ...xml.pois :type => “array” do @pois.each do |poi| xml.poi :href => poi_url(poi) do xml.name(poi.name) xml.type(poi.type) xml.review(poi.review) xml.place :href => place_url(poi.place) do xml.name poi.place.name end end endend

# AFTER ...Representative::Xml.new(xml) do |r| r.list_of :pois, @pois, :item_attributes => {:href => method(:poi_url)} do r.element :name r.element :type r.element :review r.element :place, :href => method(:place_url) do r.element :name end endend

representative

Page 17: One project, 3 gems

# XML ...Representative::Xml.new(xml) do |r| r.list_of :pois, @pois, :item_attributes => {:href => method(:poi_url)} do r.element :name r.element :type r.element :review r.element :place, :href => method(:place_url) do r.element :name end endend

# JSON ...Representative::Json.new do |r| r.list_of :pois, @pois, :item_attributes => {:href => method(:poi_url)} do r.element :name r.element :type r.element :review r.element :place, :href => method(:place_url) do r.element :name end endend.to_s

representative

Page 18: One project, 3 gems

<pois type="array"> <poi href="http://stuff.local/pois/6"> <name>Footscray Market</name> <type>See</type> <review>A frenetic covered food market.</review> <place href="http://stuff.local/places/26"> <name>Melbourne</name> </place> </poi> <poi href="http://stuff.local/pois/7"> <name>Panama Dining Room</name> <type>Eat</type> <review>Franco-Fitzroy pub grub and ersatz Manhattan views.</review> <place href="http://stuff.local/places/26"> <name>Melbourne</name> </place> </poi> <poi href="http://stuff.local/pois/8"> <name>Sydney Opera House</name> <type>See</type> <review/> <place href="http://stuff.local/places/17"> <name>Sydney</name> </place> </poi></pois>

Page 19: One project, 3 gems

[ { "name": "Footscray Market", "type": "See", "review": "A frenetic covered food market.", "place": { "name": "Melbourne" } }, { "name": "Panama Dining Room", "type": "Eat", "review": "Franco-Fitzroy pub grub and ersatz Manhattan views.", "place": { "name": "Melbourne" } }, { "name": "Sydney Opera House", "type": "See", "review": null, "place": { "name": "Sydney" } }]

representative

Page 20: One project, 3 gems

<pois/>“Atlas”

Page 21: One project, 3 gems

<pois/>“Atlas”

somethingthat wantsPOI data

Page 22: One project, 3 gems

<pois/> somethingthat wantsPOI data

fake Atlas

Page 23: One project, 3 gems

shamrack

require ‘fakeweb’FakeWeb.register_uri(:get, “http://www.example.com/hello”, :body => “Hello World!”)

require ‘webmock’stub_request(:get, “www.example.com/hello”).to_return(:body => “Hello, World!”)

require ‘sham_rack’ShamRack.at(“www.example.com”).stub.register_resource(“/hello”, “Hello, World!”)

Page 24: One project, 3 gems

shamrack

It’s just Rack!

client

ShamRack

Net::HTTP

Rack app

Page 25: One project, 3 gems

shamrack

ShamRack.at("www.example.com").rackup douse Some::Middlewareuse Some::Other::Middlewarerun MyApp.new

end

It’s just Rack!ShamRack.at("www.example.com”) do |env|

["200 OK", { "Content-type" => "text/plain" }, "Hello, world!"

]end

Page 26: One project, 3 gems

shamrack

ShamRack.at("www.example.com").sinatra doget "/hello/:subject" do "Hello, #{params[:subject]}"end

end

It’s just Rack!