Your own (little) gem: building an online business with Ruby
Upcoming SlideShare
Loading in...5
×
 

Your own (little) gem: building an online business with Ruby

on

  • 3,376 views

 

Statistics

Views

Total Views
3,376
Slideshare-icon Views on SlideShare
3,360
Embed Views
16

Actions

Likes
8
Downloads
63
Comments
0

2 Embeds 16

http://www.slideshare.net 14
http://www.linkedin.com 2

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Your own (little) gem: building an online business with Ruby Your own (little) gem: building an online business with Ruby Presentation Transcript

    • Your own gem (little) building an online business with Ruby Lindsay Holmwood <lindsay@holmwood.id.au>
    • (.com)
    • business development operations
    • have an idea
    • check that it’s profitable
    • apples oranges are both fruit
    • web store book shop are both businesses
    • financials
    • are important.
    • do them!
    • (conservative estimates are best)
    • check your tech
    • time is an expense
    • halve your deliverables
    • then halve them again
    • 1-2 core features
    • write ideas down
    • development
    • Merb (merbivore.com) development
    • Merb (merbivore.com) DataMapper (datamapper.org) development
    • Merb (merbivore.com) DataMapper (datamapper.org) MooTools (mootools.net) development
    • development
    • bootstrap
    • $ sudo gem install merb-core merb-more bootstrap
    • $ sudo gem install merb-core merb-more $ sudo gem install dm-core dm-more do_sqlite3 bootstrap
    • $ sudo gem install merb-core merb-more $ sudo gem install dm-core dm-more do_sqlite3 $ merb-gen app schoonerwatch.com bootstrap
    • $ sudo gem install merb-core merb-more $ sudo gem install dm-core dm-more do_sqlite3 $ merb-gen app schoonerwatch.com $ cd schoonerwatch.com bootstrap
    • $ sudo gem install merb-core merb-more $ sudo gem install dm-core dm-more do_sqlite3 $ merb-gen app schoonerwatch.com $ cd schoonerwatch.com $ bzr init ; bzr add $ bzr commit -m quot;initial commitquot; bootstrap
    • $ sudo gem install merb-core merb-more $ sudo gem install dm-core dm-more do_sqlite3 $ merb-gen app schoonerwatch.com $ cd schoonerwatch.com $ bzr init ; bzr add $ bzr commit -m quot;initial commitquot; s/bzr/git/g bootstrap
    • merb-gen
    • $ merb & merb-gen
    • $ merb & $ merb-gen resource pub merb-gen
    • $ merb & $ merb-gen resource pub $ bzr commit -m quot;added merb-gen'd pub resourcequot; merb-gen
    • $ merb & $ merb-gen resource pub $ bzr commit -m quot;added merb-gen'd pub resourcequot; $ vim spec/spec.opts spec/spec_helper.rb merb-gen
    • --colour --format profile spec/spec.opts
    • ... Spec::Runner.configure do |config| config.include(Merb::Test::ViewHelper) config.include(Merb::Test::RouteHelper) config.include(Merb::Test::ControllerHelper) end DataMapper.auto_migrate! spec/spec_helper.rb
    • run specs
    • $ rake spec:request run specs
    • $ rake spec:request .**...... Pending: resource(:pubs) GET contains a list of pubs (TODO) Called from ./spec/requests/pubs_spec.rb:21 resource(:pubs) GET has a list of pubs (TODO) Called from ./spec/requests/pubs_spec.rb:33 Finished in 0.322787 seconds 9 examples, 0 failures, 2 pending run specs
    • request specs
    • $ vim spec/requests/pubs_spec.rb request specs
    • $ vim spec/requests/pubs_spec.rb ... it quot;contains a sorted list of pubsquot; do @response.should have_xpath(quot;//h3[contains(.,'Cheapest')]quot;) @response.should have_xpath(quot;//h3[contains(.,'Nearest')]quot;) end request specs
    • run specs
    • $ rake spec:request run specs
    • $ rake spec:request Pending: resource(:pubs) GET has a list of pubs (TODO) Called from ./spec/requests/pubs_spec.rb:33 1) 'resource(:pubs) GET contains a sorted list of pubs' FAILED expected following text to match xpath //h3[contains(.,'Cheapest')]’ ./spec/requests/pubs_spec.rb:21: Finished in 0.411139 seconds 9 examples, 1 failure, 1 pending run specs
    • haml
    • $ vim config/dependencies.rb haml
    • $ vim config/dependencies.rb ... dependency quot;merb-hamlquot;, merb_gems_version haml
    • $ vim config/dependencies.rb ... dependency quot;merb-hamlquot;, merb_gems_version $ vim config/init.rb haml
    • $ vim config/dependencies.rb ... dependency quot;merb-hamlquot;, merb_gems_version $ vim config/init.rb ... use_template_engine :haml haml
    • hamlise view
    • $ bzr mv app/views/pubs/index.html.erb app/views/pubs/index.html.haml hamlise view
    • $ bzr mv app/views/pubs/index.html.erb app/views/pubs/index.html.haml $ vim app/views/pubs/index.html.haml hamlise view
    • $ bzr mv app/views/pubs/index.html.erb app/views/pubs/index.html.haml $ vim app/views/pubs/index.html.haml %h3 Nearest %h3 Cheapest hamlise view
    • $ bzr mv app/views/pubs/index.html.erb app/views/pubs/index.html.haml $ vim app/views/pubs/index.html.haml %h3 Nearest %h3 Cheapest $ rake spec:request Pending: resource(:pubs) GET has a list of pubs (TODO) Called from ./spec/requests/pubs_spec.rb:33 Finished in 0.389194 seconds 9 examples, 0 failures, 1 pending hamlise view tests pass!
    • model specs
    • $ vim spec/models/pubs_spec.rb model specs
    • $ vim spec/models/pubs_spec.rb 1. model specs
    • $ vim spec/models/pubs_spec.rb 1. it quot;should have name, address, pricequot; do @pubs.each do |pub| pub.name.should_not be_nil pub.address.should_not be_nil pub.price.should_not be_nil end end model specs
    • $ vim spec/models/pubs_spec.rb 2. it quot;should handle different url formatsquot; do @pubs.each do |pub| pub.url = 'mygreatpub.com.au' pub.save.should be_true pub.url = 'http://mygreatpub.com.au/' pub.save.should be_true end end model specs
    • $ vim spec/models/pubs_spec.rb 3. it quot;should consistently format + store urlsquot; do @pubs.each do |pub| adjective = %w[great swanky awesome stylish][rand(4)] pub.url = quot;#{adjective}pub.com.auquot; pub.save.should be_true pub.url.should =~ /^http://.+/$/ end end model specs
    • model specs
    • $ vim spec/models/pubs_spec.rb before(:each) do @pubs = 10.of { Pub.generate } end model specs
    • $ vim spec/models/pubs_spec.rb before(:each) do @pubs = 10.of { Pub.generate } end $ vim spec/spec_fixtures.rb require 'dm-sweatshop' Pub.fixture do { :name => ( name = %w[John Jane Jerry Justin][rand(4)] + quot;'s Pubquot;), :price => (1..30).to_a[rand(30)], :address => quot;#{(40..166).to_a[rand(126)]} Spring quot; + %w[Street Road Avenue][rand(3)], :url => quot;http://#{name.gsub(/W/, '').downcase}.com/quot; } end model specs
    • run specs
    • $ rake spec:models run specs
    • $ rake spec:models 1) NameError in 'Pub should have name, address, price' address= is not a public property 2) NameError in 'Pub should handle different url formats' address= is not a public property 3) NameError in 'Pub should consistently format + store urls' address= is not a public property Finished in 0.252169 seconds 3 examples, 3 failures run specs
    • define properties
    • $ vim app/models/pub.rb define properties
    • $ vim app/models/pub.rb class Pub include DataMapper::Resource property :id, Serial property :name, String, :nullable => false property :address, String, :nullable => false property :price, BigDecimal, :nullable => false property :url, String define properties
    • $ vim app/models/pub.rb ... def url=(string) string = quot;http://#{string}quot; unless string =~ /^http://.+// string += '/' unless string =~ //$/ @url = string end end custom setter
    • run specs
    • $ rake spec:models run specs
    • $ rake spec:models Finished in 0.488351 seconds 3 examples, 0 failures run specs win!
    • request specs
    • $ vim spec/requests/pubs_spec.rb request specs
    • $ vim spec/requests/pubs_spec.rb ... it quot;contains a list of cheapest pubsquot; do @response.should have_xpath(quot;//div[@id=’cheapest’]quot;) @response.should have_xpath(quot;//div[@id=’cheapest’]//table//tr//td[@class='name']quot;) @response.should have_xpath(quot;//div[@id=’cheapest’]//table//tr//td[@class='address']quot;) @response.should have_xpath(quot;//div[@id=’cheapest’]//table//tr//td[contains(@class,'price')]quot;) end request specs
    • run specs
    • $ rake spec:request run specs
    • $ rake spec:request Pending: resource(:pubs) GET has a list of pubs (TODO) Called from ./spec/requests/pubs_spec.rb:37 1) 'resource(:pubs) GET contains a list cheapest pubs' FAILED expected following text to match xpath //div[@id='cheapest'] ./spec/requests/pubs_spec.rb:26: Finished in 0.411139 seconds 10 examples, 1 failure, 1 pending run specs
    • build partial
    • $ vim app/views/pubs/index.html.haml build partial
    • $ vim app/views/pubs/index.html.haml %h3 Nearest %h3 Cheapest %div#cheapest = partial quot;cheapestquot; build partial
    • $ vim app/views/pubs/index.html.haml %h3 Nearest %h3 Cheapest %div#cheapest = partial quot;cheapestquot; $ vim app/views/pubs/_cheapest.html.haml build partial
    • $ vim app/views/pubs/index.html.haml %h3 Nearest %h3 Cheapest %div#cheapest = partial quot;cheapestquot; $ vim app/views/pubs/_cheapest.html.haml %table - @pubs.each_with_index do |pub, index| %tr %td.name= link_to pub.name, pub.url %td.address= pub.address %td{:class => quot;price cheapest-#{index}quot;} = '$' + sprintf(quot;%.2fquot;, pub.price) build partial
    • run specs
    • $ rake spec:request run specs
    • $ rake spec:request Pending: resource(:pubs) GET has a list of pubs (TODO) Called from ./spec/requests/pubs_spec.rb:37 Finished in 0.854704 seconds 10 examples, 0 failures, 1 pending run specs
    • nearest
    • $ vim app/views/pubs/index.html.haml nearest
    • $ vim app/views/pubs/index.html.haml %h3 Nearest %div#nearest = partial quot;nearestquot; %h3 Cheapest %div#cheapest = partial quot;cheapestquot; nearest
    • $ vim app/views/pubs/index.html.haml %h3 Nearest %div#nearest = partial quot;nearestquot; %h3 Cheapest %div#cheapest = partial quot;cheapestquot; $ vim app/views/pubs/_nearest.html.haml nearest
    • $ vim app/views/pubs/index.html.haml %h3 Nearest %div#nearest = partial quot;nearestquot; %h3 Cheapest %div#cheapest = partial quot;cheapestquot; $ vim app/views/pubs/_nearest.html.haml %div#map{:style => quot;width: 800px; height: 600px; margin: auto;quot;} nearest
    • global layout
    • $ vim app/views/layout/application.html.erb global layout
    • $ vim app/views/layout/application.html.erb <%= js_include_tag 'mootools' %> <%= js_include_tag 'SimpleTabs' %> <%= js_include_tag 'application' %> <script src=quot;http://maps.google.com/maps?file=api&amp;v=2&amp;key= <%= Merb.config.gmaps_api_key %>quot; type=quot;text/javascriptquot;></script> global layout
    • $ vim app/views/layout/application.html.erb <%= js_include_tag 'mootools' %> <%= js_include_tag 'SimpleTabs' %> <%= js_include_tag 'application' %> <script src=quot;http://maps.google.com/maps?file=api&amp;v=2&amp;key= <%= Merb.config.gmaps_api_key %>quot; type=quot;text/javascriptquot;></script> $ vim config/environments/development.rb c[:gmaps_api_key] = quot;fooquot; api key
    • $ vim app/views/layout/application.html.erb <%= js_include_tag 'mootools' %> <%= js_include_tag 'SimpleTabs' %> <%= js_include_tag 'application' %> <script src=quot;http://maps.google.com/maps?file=api&amp;v=2&amp;key= <%= Merb.config.gmaps_api_key %>quot; type=quot;text/javascriptquot;></script> $ vim config/environments/production.rb c[:gmaps_api_key] = quot;barquot; production api key
    • $ vim public/javascripts/application.js window.addEvent('domready', function() { }); nearest
    • $ vim public/javascripts/application.js window.addEvent('domready', function() { if (GBrowserIsCompatible()) { var map = new GMap2($(quot;mapquot;)); map.enableScrollWheelZoom(); map.setCenter(new GLatLng(-33.86336, 151.207151), 12); var geocoder = new GClientGeocoder(); /* geocode top-ten addresses */ $$('div#cheapest tr').each( function(element) { showAddress(map, geocoder, element); }); } }); dash o’ javascript
    • $ vim public/javascripts/application.js function showAddress(map, geocoder, element) { var name = element.getElements('td.name a').get('html'); var address = element.getChildren('td.address').get('html'); var price = element.getElements('td.price').get('html'); var link = element.getElements('td.name a').get('href'); geocoder.getLatLng(address, function(point) { if (point) { var marker = new GMarker(point); marker.bindInfoWindowHtml(quot;<h4>quot; + name + quot;</h4>quot; + ... ); map.addOverlay(marker); } }); } custom geocoder
    • some stylesheet foo
    • slices freezing param-protection action-args
    • operations
    • monitoring
    • collectd
    • lightweight statistics collection daemon
    • lightweight statistics collection daemon
    • LoadPlugin cpu LoadPlugin df LoadPlugin disk LoadPlugin interface LoadPlugin load LoadPlugin memory LoadPlugin network LoadPlugin processes LoadPlugin rrdtool LoadPlugin socket LoadPlugin swap LoadPlugin users ...
    • <Plugin df> MountPoint quot;/quot; </Plugin> <Plugin interface> Interface quot;eth0quot; Interface quot;eth1quot; </Plugin> ...
    • <Plugin rrdtool> DataDir quot;/var/lib/collectd/rrdquot; CacheTimeout 180 CacheFlush 7200 </Plugin> <Plugin network> Server quot;my.monitoring.server.netquot; # Port 25826 </Plugin> ...
    • <Plugin processes> Process quot;rubyquot; # Process quot;mysqldquot; </Plugin> ...
    • eek!
    • collectd-nagios
    • $ /usr/bin/collectd-nagios -s /var/run/collectd/socket -n cpu-0/cpu-idle -H my.server.com -w 40: -c 10: 0 critical, 1 warning, 0 okay | value=34.000000;;;; $ /usr/bin/collectd-nagios -s /var/run/collectd/socket -n df/df-root -H my.server.com -d free -c 314572800: -w 524288000: 0 critical, 0 warning, 1 okay |free=924288000.0;;;;
    • 0 good 1 bad 2 ugly
    • $ ls /var/lib/collectd/rrd/my.server.com cpu-0 cpu-1 df disk-sda disk-sda1 interface load memory swap users
    • apache apcups apple sensors ascent battery cpu cpufreq csv df disk dns email entropy exec filecount hddtemp interface iptables ipmi ipvs irqs libvirt load logfile mbmon memcached memory multimeter mysql netlink network nfs nginx notify_desktop notify_email ntpd nut onewire perl ping postgresql powerdns processes rrdtool sensors serial snmp swap syslog tail tape tcpconns teamspeak2 thermal unixsock users uuid vmem vserver wireless
    • apache apcups apple sensors ascent battery cpu cpufreq csv df disk dns email entropy exec filecount hddtemp interface iptables ipmi ipvs irqs libvirt load logfile mbmon memcached memory multimeter mysql netlink network nfs nginx notify_desktop notify_email ntpd nut onewire perl ping postgresql powerdns processes rrdtool sensors serial snmp swap syslog tail tape tcpconns teamspeak2 thermal unixsock users uuid vmem vserver wireless
    • configuration management
    • Puppet language => client/server => library
    • manifests types classes nodes
    • manifests => describe types classes nodes
    • manifests types => manage classes nodes
    • package { apache2: ensure => present }
    • package { apache2: ensure => present } file { quot;/etc/apache2/apache2.confquot;, content => template(quot;/etc/puppet/ config/classes/httpd_server/ httpd.conf.erbquot;), mode => 644 }
    • package { apache2: ensure => present } file { quot;/etc/apache2/apache2.confquot;, content => template(quot;/etc/puppet/ config/classes/httpd_server/ httpd.conf.erbquot;), mode => 644 } service { apache2: ensure => running, subscribe => File[quot;/etc/apache2/ apache2.confquot;] }
    • manifests types => manage classes nodes
    • manifests types classes => group nodes
    • package { apache2: ensure => present } # ...
    • class apache2 { package { apache2: ensure => present } # ... }
    • class passenger inherits apache2 { package { libapache2-mod-passenger: ensure => present } # ... }
    • define apache2 ($port) { package { apache2: ensure => present } # ... }
    • manifests types classes => group nodes
    • manifests types classes nodes => apply
    • node quot;srv01.skippy.comquot; { include passenger }
    • node quot;srv01.skippy.comquot; { include passenger }
    • node quot;srv01.skippy.comquot; { include passenger } node quot;server02.skippy.comquot; { include passenger } node quot;server03.skippy.comquot; { include passenger }
    • node quot;merbnodequot; { include passenger } node quot;server01.skippy.comquot; inherits passenger {} node quot;server02.skippy.comquot; inherits passenger {} node quot;server03.skippy.comquot; { include customisation }
    • versionable infrastructure
    • versionable infrastructure (for free)
    • $ cd skippy.puppet.lindsay $ git init # puppet magic happens $ git push
    • # puppetd --test --debug
    • resources
    • getting real seth godin wiki.merbivore.com
    • Thank you! (and questions)