planetruby2feed 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b32835b57c87b1aae62b06f117b33cf663595af2
4
+ data.tar.gz: 4e34add443e01c57d643201b20279169019c95fb
5
+ SHA512:
6
+ metadata.gz: 0822d10d058aecfa05421e7a749ab1ba1e9bbdafb75256351de439f089aba54694526d64e496956cb099410b66458b278fda834d2f765eb1b8ee5236071306a2
7
+ data.tar.gz: 1c1e121eae4951d724464eb3d67550def2d74492b1f01d60e1c82368de19aa7196d353f8b36328036094ec6eb88c0230e39c9540407921f7c8d18d0d5a57fad5
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .ruby-version
19
+ *.swp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in planetruby2feed.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Tommaso Visconti
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Planetruby2feed
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'planetruby2feed'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install planetruby2feed
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'planetruby2feed'
7
+
8
+ Planetruby2feed::Base.run!
@@ -0,0 +1,30 @@
1
+ require 'logger'
2
+
3
+ require "planetruby2feed/constants"
4
+ require "planetruby2feed/version"
5
+ require "planetruby2feed/scraper"
6
+ require "planetruby2feed/parser"
7
+ require "planetruby2feed/webserver"
8
+
9
+ module Planetruby2feed
10
+ class Base
11
+ include Planetruby2feed::Scraper
12
+ include Planetruby2feed::Parser
13
+
14
+ attr_accessor :posts
15
+
16
+ def initialize
17
+ @logger = Logger.new(STDOUT)
18
+ @logger.level = Logger::WARN
19
+ @posts = []
20
+ end
21
+
22
+ def self.run!
23
+ @planet = self.new
24
+ @planet.get_page
25
+ @planet.find_posts
26
+ Planetruby2feed::Webserver.set :posts, @planet.posts
27
+ Planetruby2feed::Webserver.run!
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module Planetruby2feed
2
+ URL = 'http://www.planetrubyonrails.com/'
3
+ end
@@ -0,0 +1,29 @@
1
+ require 'nokogiri'
2
+
3
+ module Planetruby2feed
4
+ module Parser
5
+
6
+ def find_posts
7
+ @webpage.css('.main div.post', '.main div.star-post').each do |post|
8
+ @posts << parse_post(post)
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def parse_post(post)
15
+ begin
16
+ title = post.css('> h2 a').text.strip
17
+ link = post.css('> h2 a').attr('href').value
18
+ star_post = (post.attr('class') == 'star-post')
19
+
20
+ post.css('> h2').remove
21
+ post.css('span.small-text').remove
22
+
23
+ return { title: title, link: link, star_post: star_post, content: post.to_html }
24
+ rescue
25
+ nil
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ require 'nokogiri'
2
+ require 'open-uri'
3
+
4
+ module Planetruby2feed
5
+ module Scraper
6
+ attr_accessor :webpage
7
+
8
+ def analyze
9
+ get_page
10
+ end
11
+
12
+ def get_page
13
+ begin
14
+ @webpage = Nokogiri::HTML(open(Planetruby2feed::URL))
15
+ rescue Exception => e
16
+ @logger.fatal e.message
17
+ end
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,3 @@
1
+ module Planetruby2feed
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,18 @@
1
+ require 'sinatra/base'
2
+ require 'builder'
3
+ require 'pry'
4
+
5
+ module Planetruby2feed
6
+ class Webserver < Sinatra::Application
7
+ set :static, true
8
+ set :public_folder, File.expand_path('../../../resources/assets/', __FILE__)
9
+
10
+ set :views, File.expand_path('../../../resources/views/', __FILE__)
11
+ set :haml, { :format => :html5 }
12
+
13
+ get '/rss' do
14
+ @posts = settings.posts
15
+ builder :rss
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'planetruby2feed/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "planetruby2feed"
8
+ spec.version = Planetruby2feed::VERSION
9
+ spec.authors = ["Tommaso Visconti"]
10
+ spec.email = ["tommaso.visconti@gmail.com"]
11
+ spec.description = %q{Transform planetrubyonrails.com to RSS feed}
12
+ spec.summary = %q{Creates a RSS feed reading entries from planetrubyonrails.com}
13
+ spec.homepage = "https://bitbucket.org/tommyblue/planetruby2feed"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "pry"
25
+
26
+ spec.add_runtime_dependency "nokogiri"
27
+ spec.add_runtime_dependency "sinatra"
28
+ spec.add_runtime_dependency "builder"
29
+ end
@@ -0,0 +1,18 @@
1
+ xml.instruct! :xml, version: '1.0'
2
+ xml.rss version: "2.0" do
3
+ xml.channel do
4
+ xml.title "PlanetRubyOnRails2Feed"
5
+ xml.description "PlantetRubyOnRails RSS version"
6
+ xml.link "http://www.planetrubyonrails.com"
7
+
8
+ @posts.each do |post|
9
+ xml.item do
10
+ xml.title post[:title]
11
+ xml.link post[:link]
12
+ xml.description post[:content]
13
+ xml.pubDate Time.now.rfc822()
14
+ xml.guid post[:link]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
3
+
4
+ require 'pry'
5
+ require 'planetruby2feed'
6
+
7
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
8
+ RSpec.configure do |config|
9
+ config.treat_symbols_as_metadata_keys_with_true_values = true
10
+ config.run_all_when_everything_filtered = true
11
+ config.filter_run :focus
12
+
13
+ # Run specs in random order to surface order dependencies. If you find an
14
+ # order dependency and want to debug it, you can fix the order by providing
15
+ # the seed, which is printed after each run.
16
+ # --seed 1234
17
+ config.order = 'random'
18
+ end
@@ -0,0 +1,514 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
4
+ <head>
5
+ <title>PlanetRubyOnRails - has_many :blogs, :through => :feeds</title>
6
+ <link href="/stylesheets/planet.css?1285519206" media="screen" rel="stylesheet" type="text/css" />
7
+ </head>
8
+ <body>
9
+
10
+ <div id="contents" class="outer">
11
+
12
+ <div class="header">
13
+ <div class="left-header"><br />
14
+ <img src="/images/theme/planet-logo.gif">
15
+ </div>
16
+ <div class="right-header">
17
+
18
+ <ul id="pages" class="menu">
19
+ <li><a href="http://www.planetrubyonrails.com">Home</a></li>
20
+ <li><a href="http://www.planetrubyonrails.com/pages/channels">Channels</a></li>
21
+ </ul>
22
+ </div>
23
+ </div>
24
+
25
+
26
+
27
+ <div id="container" class="inner">
28
+ <div class="main">
29
+
30
+
31
+
32
+
33
+
34
+ <div class="post">
35
+
36
+ <h2>
37
+
38
+ <a href="http://www.pinupgeek.com/trip-to-louisville/">Upcoming Trip to Louisville</a>
39
+ </h2>
40
+ <span class="small-text">Posted about 7 hours back at <a href="http://www.pinupgeek.com/">pinupgeek - Home</a></span>
41
+ <p><p>Summer is upon us and it’s time for some of us to take a vacation. For me that means a brief trip to <a href='http://www.louisvilleky.gov/' title='Louisville, Kentucky' target='_blank'>Louisville, Kentucky</a>.</p>
42
+ <p>I’ve been to Louisville several times, but there are a few new spots that I’d like to visit this trip. For those of you who’ve never been, here are some things to check out if you ever get the chance.</p>
43
+ <h3>Tourist Attractions in Louisville</h3>
44
+ <p>Louisville isn’t a huge city (it’s <a href='http://en.wikipedia.org/wiki/List_of_United_States_cities_by_population' title='List of United States cities by population' target='_blank'>27th in the country by population</a>), but at over half a million people, it isn’t too small either. And in a city of this size, there are plenty of attractions to see.</p>
45
+ <h4>Downtown Louisville</h4>
46
+ <p>In addition to being a bustling business district, downtown Louisville is very welcoming to tourists. These are just some of the museums in the area:</p>
47
+ <ul>
48
+ <li><span style='line-height: 13px;'>Frazier History Museum</span></li>
49
+ <li>Glassworks</li>
50
+ <li>Louisville Slugger Museum &amp; Factory (they’ll give you a free miniature baseball bat if you take a tour)</li>
51
+ <li>Kentucky Science Center</li>
52
+ <li>Kentucky Museum of Art and Craft</li>
53
+ <li>21c Museum and Hotel</li>
54
+ <li>The Muhammad Ali Center</li>
55
+ <li>The Kentucky Center for the Performing Arts</li>
56
+ </ul>
57
+ <p>And if you’re a coffee drinker (like <a href='http://www.pinupgeek.com/' title='Pin-Up Geek'>any respectable geek</a> is), be sure to check out <a href='http://www.thecoffeecompass.com/concept-espresso-bar-louisville-sunergos/' title='Concept Espresso Bar Invades Downtown Louisville' target='_blank'>the new Sunergos Espresso bar on 2nd Street</a> while you’re downtown.</p>
58
+ <h4>Churchill Downs</h4>
59
+ <p>When most people think of Louisville, the Kentucky Derby comes to mind. Of course it’s held in the beautiful <a href='http://www.churchilldowns.com/' title='Churchill Downs' target='_blank'>Churchill Downs</a>. Unfortunately I’m going to be a few months late for the Derby, but there are other horse races held there as well.</p>
60
+ <h3>Louisville Restaurants</h3>
61
+ <p>In addition to the other tourist attractions, Louisville hosts a ton of delicious restaurants. In fact, it was <a href='http://www.bonappetit.com/blogsandforums/blogs/bafoodist/2009/09/americas-foodiest-small-town-r.html' title='America&apos;s Foodiest Small Town Runners-Up' target='_blank'>recently named</a> one of the “foodiest cities” in America.</p>
62
+ <p>I’ve been to a lot of Louisville’s restaurants on previous trips, but this time I’m looking forward to trying out <a href='http://fourpegsbeerlounge.com/' title='Four Pegs Beer Lounge' target='_blank'>a new pub/beer bar — Four Pegs Beer Lounge</a>. Supposedly they have a delicious chicken waffle sandwich that I’m dying to try.</p>
63
+ <h3>Future Geekiness</h3>
64
+ <p>I’ll be gone for a few days, but when I return expect some more posts about <a href='http://www.pinupgeek.com/getting-started-with-rails/' title='Getting Started with Rails' target='_blank'>Ruby on Rails</a> and some other recent projects.</p></p>
65
+ </div>
66
+
67
+
68
+
69
+
70
+ <div class="post">
71
+
72
+ <h2>
73
+
74
+ <a href="http://feedproxy.google.com/~r/GiantRobotsSmashingIntoOtherGiantRobots/~3/eFU68XrpCMs/53756972631">Episode 54: Build your stuff on the side and have a good time</a>
75
+ </h2>
76
+ <span class="small-text">Posted about 20 hours back at <a href="http://giantrobots.thoughtbot.com/">GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home</a></span>
77
+ <p><a href='http://learn.thoughtbot.com/podcast/54'>Episode 54: Build your stuff on the side and have a good time</a>: <p>In this episode, Ben Orenstein is joined by 17 year old Jack Kaufman, author of The Found a Business Book. Ben and Jack discuss Jack’s inspiration for the book and how he got all his interviews, the other opportunities it’s led too, the common themes he uncovered in his interviews, the differences between those who got funding and bootstrappers, working on the book while in highschool, marketing he’s doing, his plans for the future, the issue with college computer science programs, his fears about the future, and much more.</p>
78
+
79
+ <ul><li><a href='http://learn.thoughtbot.com/podcast/54'>Episode Notes and Links</a></li>
80
+ <li><a href='http://itunes.apple.com/us/podcast/giant-robots-smashing-into/id535121941'>Subscribe via iTunes</a></li>
81
+ <li><a href='http://learn.thoughtbot.com/podcast.xml'>Subscribe via RSS</a></li>
82
+ <li><a href='http://learn.thoughtbot.com/podcast/54.mp3'>Direct Download</a></li>
83
+ </ul></p>
84
+ </div>
85
+
86
+
87
+
88
+
89
+ <div class="post">
90
+
91
+ <h2>
92
+
93
+ <a href="http://synaphy.com.au/agile-software-development-principles/?utm_source=rss&utm_medium=rss&utm_campaign=agile-software-development-principles">Agile Software Development Principles</a>
94
+ </h2>
95
+ <span class="small-text">Posted 2 days back at <a href="http://synaphy.com.au/blog">Synaphy - Blog</a></span>
96
+ <p><p>Agile software development is about delivering the best possible result to customers for the fairest price. Agile focuses on people interactions, working software and the recognition that change in a software project is not something to be feared or negotiated, but wholeheartedly embraced.</p>
97
+ <p>Some of the key components of an Agile project that we put great emphasis on are:<br/>
98
+ <span id='more-29'/></p>
99
+ <ul>
100
+ <li>Frequent Customer Interaction</li>
101
+ <li>Working Software</li>
102
+ </ul>
103
+ <h3>Frequent Customer Interaction</h3>
104
+ <p>This is the only way to find the best solution to a problem. We work closely with our customers to define and refine a software application as it is being built. It is impossible to write down everything about a piece of software at the start of a project – if everything was known about the software, you’d be able to buy one off the shelf that met your needs exactly!</p>
105
+ <p>That’s why we frequently deliver… </p>
106
+ <h3>Working Software</h3>
107
+ <p>The Agile approach puts strict timeboxes around development. We prefer to work in one- to two-week iterations. At the end of each iteration, you will receive a working, fully tested and deployable application.</p>
108
+ <p>You may find that an early iteration is already delivering sufficient business value – you can decide to stop a project at any time, no questions asked and no strings attached.</p>
109
+ <h3>Why No Fixed Price?</h3>
110
+ <p>We don’t believe that fixing the price of a software development project can result in a fair outcome. With an Agile approach, you pay <em>exactly</em> what the application is worth – no more and no less.</p>
111
+ <h3>Minimal Risk</h3>
112
+ <p>While fixed-price projects may seem like a less risky alternative before the start of a project, consider this:</p>
113
+ <ul>
114
+ <li>when the developer runs out of money because they underquoted the project, the quality of the project <strong>will</strong> suffer.</li>
115
+ <li>when you have a great idea for a change to take the application to the next level – sorry, but that wasn’t in the original quote</li>
116
+ <li>you will spend inordinate amounts of time negotiating changes – time that could be better spent envisaging great new features for your application</li>
117
+ </ul>
118
+ <p>So if you would like to know more about achieving the best possible outcome for the fairest price, <a href='http://synaphy.com.au/contact'>talk to us</a></p>
119
+ <p>The post <a href='http://synaphy.com.au/agile-software-development-principles/'>Agile Software Development Principles</a> appeared first on <a href='http://synaphy.com.au/'>Synaphy</a>.</p></p>
120
+ </div>
121
+
122
+
123
+
124
+
125
+ <div class="post">
126
+
127
+ <h2>
128
+
129
+ <a href="http://synaphy.com.au/featured-post-2/?utm_source=rss&utm_medium=rss&utm_campaign=featured-post-2">Featured Post 2</a>
130
+ </h2>
131
+ <span class="small-text">Posted 2 days back at <a href="http://synaphy.com.au/blog">Synaphy - Blog</a></span>
132
+ <p><p><img class='alignnone size-full wp-image-22' src='http://synaphy.com.au/wp-content/uploads/2013/06/featured-2.jpg' alt='featured-2' width='100%'/><br/>
133
+ This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind.<br/>
134
+ This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind. This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind.<br/>
135
+ This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind.<br/>
136
+ This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind. This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind.</p>
137
+ <p>The post <a href='http://synaphy.com.au/featured-post-2/'>Featured Post 2</a> appeared first on <a href='http://synaphy.com.au/'>Synaphy</a>.</p></p>
138
+ </div>
139
+
140
+
141
+
142
+
143
+ <div class="post">
144
+
145
+ <h2>
146
+
147
+ <a href="http://synaphy.com.au/featured-post-3/?utm_source=rss&utm_medium=rss&utm_campaign=featured-post-3">Featured Post 3</a>
148
+ </h2>
149
+ <span class="small-text">Posted 2 days back at <a href="http://synaphy.com.au/blog">Synaphy - Blog</a></span>
150
+ <p><p><img class='alignnone size-full wp-image-18' src='http://synaphy.com.au/wp-content/uploads/2013/06/featured-3.jpg' alt='featured-3' width='100%'/></p>
151
+ <p>This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind.<br/>
152
+ This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind. This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind.<br/>
153
+ This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind.<br/>
154
+ This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind. This is an example of a WordPress post, you could edit this to put information about yourself or your site so readers know where you are coming from. You can create as many posts as you like in order to share with your readers what exactly is on your mind.</p>
155
+ <p>The post <a href='http://synaphy.com.au/featured-post-3/'>Featured Post 3</a> appeared first on <a href='http://synaphy.com.au/'>Synaphy</a>.</p></p>
156
+ </div>
157
+
158
+
159
+
160
+
161
+ <div class="post">
162
+
163
+ <h2>
164
+
165
+ <a href="http://synaphy.com.au/international-solutions/?utm_source=rss&utm_medium=rss&utm_campaign=international-solutions">International Solutions</a>
166
+ </h2>
167
+ <span class="small-text">Posted 2 days back at <a href="http://synaphy.com.au/blog">Synaphy - Blog</a></span>
168
+ <p><p><img class='alignnone size-full wp-image-18' src='http://synaphy.com.au/wp-content/uploads/2013/06/featured-3.jpg' alt='featured-3' width='100%'/></p>
169
+ <p>The recent technological advances in communications and travel technologies have removed the barriers that used to make overseas business difficult. Thanks to the internet, cell phones, jet airplanes, Synaphy is able to provide international solutions to practically any country — whether domestic or foreign.<span id='more-17'/></p>
170
+ <h3>Synaphy’s International Clients</h3>
171
+ <p>We have already worked with several companies overseas:</p>
172
+ <h5>Four Pegs Beer Lounge</h5>
173
+ <h5>The Coffee Compass</h5>
174
+ <h5>Lyndon Animal Clinic</h5>
175
+ <h5>Avid Netizen</h5>
176
+ <h3>Will We Add You to this List?</h3>
177
+ <p>Don’t let distance stand between us! If you’re interested in our services, <a href='http://synaphy.com.au/contact/' title='Contact Details'>drop us a line</a> and let us know how we can help.</p>
178
+ <p>The post <a href='http://synaphy.com.au/international-solutions/'>International Solutions</a> appeared first on <a href='http://synaphy.com.au/'>Synaphy</a>.</p></p>
179
+ </div>
180
+
181
+
182
+
183
+
184
+ <div class="post">
185
+
186
+ <h2>
187
+
188
+ <a href="http://synaphy.com.au/featured-post-1/?utm_source=rss&utm_medium=rss&utm_campaign=featured-post-1">Featured Post 1</a>
189
+ </h2>
190
+ <span class="small-text">Posted 2 days back at <a href="http://synaphy.com.au/blog">Synaphy - Blog</a></span>
191
+ <p><p><img class='alignnone size-full wp-image-7' src='http://synaphy.com.au/wp-content/uploads/2013/06/featured-1.jpg' height='400' alt='featured-1' width='870'/></p>
192
+ <p>The post <a href='http://synaphy.com.au/featured-post-1/'>Featured Post 1</a> appeared first on <a href='http://synaphy.com.au/'>Synaphy</a>.</p></p>
193
+ </div>
194
+
195
+
196
+
197
+
198
+ <div class="post">
199
+
200
+ <h2>
201
+
202
+ <a href="http://synaphy.com.au/hello-world/">Hello world!</a>
203
+ </h2>
204
+ <span class="small-text">Posted 2 days back at <a href="http://synaphy.com.au/blog">Synaphy - Blog</a></span>
205
+ <p><p>Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!</p>
206
+ <p>The post <a href='http://synaphy.com.au/hello-world/'>Hello world!</a> appeared first on <a href='http://synaphy.com.au/'>Synaphy</a>.</p></p>
207
+ </div>
208
+
209
+
210
+
211
+
212
+ <div class="post">
213
+
214
+ <h2>
215
+
216
+ <a href="http://synaphy.com.au/hello-world/?utm_source=rss&utm_medium=rss&utm_campaign=hello-world">Hello world!</a>
217
+ </h2>
218
+ <span class="small-text">Posted 2 days back at <a href="http://synaphy.com.au/blog">Synaphy - Blog</a></span>
219
+ <p><p>Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!</p>
220
+ <p>The post <a href='http://synaphy.com.au/hello-world/'>Hello world!</a> appeared first on <a href='http://synaphy.com.au/'>Synaphy</a>.</p></p>
221
+ </div>
222
+
223
+
224
+
225
+
226
+ <div class="post">
227
+
228
+ <h2>
229
+
230
+ <a href="http://clarkware.com/blog/2013/6/22/little-griz">Little Griz</a>
231
+ </h2>
232
+ <span class="small-text">Posted 2 days back at <a href="http://www.clarkware.com/cgi/blosxom">Mike Clark</a></span>
233
+ <p><a href='http://www.flickr.com/photos/clarkware/9112171174/' title='Little Griz'><img src='http://farm3.staticflickr.com/2835/9112171174_a0850ccbef_c.jpg' height='595' alt='Little Griz' width='800'/></a></p>
234
+ </div>
235
+
236
+
237
+
238
+
239
+ <div class="post">
240
+
241
+ <h2>
242
+
243
+ <a href="http://feedproxy.google.com/~r/GiantRobotsSmashingIntoOtherGiantRobots/~3/kZBWfLyXgRE/53593110106">Summer Sale: 40% Off Everything on Learn</a>
244
+ </h2>
245
+ <span class="small-text">Posted 3 days back at <a href="http://giantrobots.thoughtbot.com/">GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS - Home</a></span>
246
+ <p><p>You know what we’ve never done on <a href='http://learn.thoughtbot.com/learnsale'>Learn</a> before? Offered a sale on every product on the site!</p>
247
+
248
+ <p>We’ve decided to take a quick break from smashing robots to offer 40% off on everything we’ve ever released.</p>
249
+
250
+ <p>You could save over $400 on one of our awesome workshops, $20 off one of our books or pay just $9 for one of our screencasts. Nine dollars! You can’t afford to not take advantage of this! The more you spend the more you save!</p>
251
+
252
+ <p><a href='http://learn.thoughtbot.com/sale'>View a complete product listing and get 40% off</a>.</p>
253
+
254
+ <p>Act now! <b>This sale ends Tuesday the 25th at midnight.</b> Void where prohibited. Use only as directed.</p></p>
255
+ </div>
256
+
257
+
258
+
259
+
260
+ <div class="post">
261
+
262
+ <h2>
263
+
264
+ <a href="http://clarkware.com/blog/2013/6/21/my-first-day">My First Day</a>
265
+ </h2>
266
+ <span class="small-text">Posted 4 days back at <a href="http://www.clarkware.com/cgi/blosxom">Mike Clark</a></span>
267
+ <p><a href='http://www.flickr.com/photos/clarkware/9101349879/' title='My First Day'><img src='http://farm6.staticflickr.com/5533/9101349879_e3650fb244_c.jpg' height='626' alt='My First Day' width='800'/></a></p>
268
+ </div>
269
+
270
+
271
+
272
+
273
+ <div class="star-post">
274
+
275
+ <h2>
276
+
277
+ <img src="/images/theme/star.png"/>
278
+
279
+ <a href="http://feedproxy.google.com/~r/Ruby5/~3/_QoJLf1lfbA/416-episode-380-june-21st-2013">Episode #380 - June 21st, 2013</a>
280
+ </h2>
281
+ <span class="small-text">Posted 4 days back at <a href="http://ruby5.envylabs.com/">Ruby5</a></span>
282
+ <p><p>
283
+ Develop your fat-client JS apps with lineman, learn Elixer with PeepCode, Github's Repository Next, benchmarking ruby, motion-accessibility, and when projects disappear all in this episode of Ruby5!
284
+ <br/>
285
+ </p>
286
+ <p><a href='http://ruby5.envylabs.com/episodes/416-episode-380-june-21st-2013' rel='nofollow'>Listen to this episode on Ruby5</a></p>
287
+ <p>
288
+ <em><a href='http://www.newrelic.com/index.html?utm_source=RBY5&utm_medium=banner&utm_content=&utm_campaign=RPM&utm_term=0&mpc=BA-RBY5-RPM-EN-0-0-0'>This episode is sponsored by New Relic</a></em>
289
+ <br/>
290
+ New Relic is _the_ all-in-one web performance analytics product. It lets you manage and monitor web application performance, from the browser down to the line of code. With Real User Monitoring, New Relic users can see browser response times by geographical location of the user, or by browser type.
291
+ </p>
292
+ <p>
293
+ <em><a href='https://github.com/testdouble/lineman'>Lineman</a></em>
294
+ <br/>
295
+ Lineman makes it easy to develop and test your JS-heavy application without a server. It comes with everything you need to get going right out of the box.
296
+ </p>
297
+ <p>
298
+ <em><a href='https://peepcode.com/products/elixir'>Meet Elixir</a></em>
299
+ <br/>
300
+ Jose Valim takes you through his language while building a real-world library to parse HTTP streaming metadata files.
301
+ </p>
302
+ <p>
303
+ <em><a href='https://github.com/blog/1529-repository-next'>Repository Next</a></em>
304
+ <br/>
305
+ Github is getting a major redesign!
306
+ </p>
307
+ <p>
308
+ <em><a href='http://rubylearning.com/blog/2013/06/19/how-do-i-benchmark-ruby-code/'>How To Benchmark Ruby</a></em>
309
+ <br/>
310
+ So you've got some Ruby code and you want to make it faster?
311
+ </p>
312
+ <p>
313
+ <em><a href='http://behindthecurtain.us/2013/06/19/motion-accessibility/'>Motion-Accessibility</a></em>
314
+ <br/>
315
+ Accessibility in your iOS apps has never been easier.
316
+ </p>
317
+ <p>
318
+ <em><a href='https://groups.google.com/forum/?fromgroups#%21topic/espresso-framework/toKzHfHFQkk'>When Projects Disappear</a></em>
319
+ <br/>
320
+ Another project (and maintainer) seem to have vanished overnight. Was it foul play? Were they abducted by aliens? We may never know!
321
+ </p></p>
322
+ </div>
323
+
324
+
325
+
326
+
327
+ <div class="post">
328
+
329
+ <h2>
330
+
331
+ <a href="http://feedproxy.google.com/~r/igvita/~3/uDo94--3uRw/">HTTP Archive + BigQuery = Web Performance Answers</a>
332
+ </h2>
333
+ <span class="small-text">Posted 5 days back at <a href="http://www.igvita.com/blog">igvita.com</a></span>
334
+ <p><p><img class='left' src='http://www.igvita.com/posts/13/ha-bigquery.png'/><a href='http://httparchive.org/'>HTTP Archive</a> is a treasure trove of web performance data. Launched in late 2010, the project crawls over 300,000 most popular sites twice a month and records how the web is built: number and types of resources, size of each resource, whether the resources are compressed or marked as cacheable, times to render the page, time to first paint, and so on - you get the point.</p>
335
+
336
+ <p>The HTTP Archive site itself provides a number <a href='http://httparchive.org/interesting.php'>interesting stats</a> and <a href='http://httparchive.org/trends.php'>aggregate trends</a>, but the data on the site only scratches the surface of the kinds of questions you can ask! To satisfy your curiousity, all you need to do is download and import ~400GB of raw SQL/CSV data. Easy, right? Yeah, not really. Instead, <strong>wouldn't it be nice if we had the full dataset of all the HTTP Archive data to query on demand, and with ad-hoc questions?</strong></p>
337
+
338
+ <h2>Google BigQuery + HTTP Archive</h2>
339
+
340
+ <p>Well, good news, now you can satisfy your curiosity in minutes (or seconds, even). The full HTTP Archive dataset is now available on BigQuery! To get started, point your browser to <a href='https://bigquery.cloud.google.com/'>bigquery.cloud.google.com</a> and click the down arrow beside "API Project": <code>Switch to project &gt; Display project &gt; enter "httparchive"</code></p>
341
+
342
+ <p><img class='center' src='http://www.igvita.com/posts/13/bigquery-instructions.png' style='width: 100%;'/></p>
343
+
344
+ <p>Once the project is imported, expand the project in left navigation and you'll see a collection of tables for individual pages and request data for each run of the HTTP Archive crawler. From there, pull up the SQL console, and go nuts! For example, let's start simple: <strong>what is the median time to first render?</strong></p>
345
+
346
+ <div class='highlight'><pre><code class='sql'><span class='k'>SELECT</span>
347
+ <span class='n'>NTH</span><span class='p'>(</span><span class='mi'>50</span><span class='p'>,</span> <span class='n'>quantiles</span><span class='p'>(</span><span class='n'>renderStart</span><span class='p'>,</span><span class='mi'>101</span><span class='p'>))</span> <span class='n'>median</span><span class='p'>,</span>
348
+ <span class='n'>NTH</span><span class='p'>(</span><span class='mi'>75</span><span class='p'>,</span> <span class='n'>quantiles</span><span class='p'>(</span><span class='n'>renderStart</span><span class='p'>,</span><span class='mi'>101</span><span class='p'>))</span> <span class='n'>seventy_fifth</span><span class='p'>,</span>
349
+ <span class='n'>NTH</span><span class='p'>(</span><span class='mi'>90</span><span class='p'>,</span> <span class='n'>quantiles</span><span class='p'>(</span><span class='n'>renderStart</span><span class='p'>,</span><span class='mi'>101</span><span class='p'>))</span> <span class='n'>ninetieth</span>
350
+ <span class='k'>FROM</span> <span class='p'>[</span><span class='n'>runs</span><span class='p'>.</span><span class='mi'>2013</span><span class='n'>_06_01_pages</span><span class='p'>]</span>
351
+ </code></pre></div>
352
+
353
+
354
+ <p>And the answer is: <strong>2.2s median, 3.3s for 75th percentile, and 4.7s for 90th percentile</strong>. BigQuery provides a number of convenience functions, such as quantiles, statistical approximations, extended regular expression matching and extraction, and a lot more. Check out the <a href='https://developers.google.com/bigquery/docs/query-reference'>query reference</a> and <a href='https://developers.google.com/bigquery/docs/query-cookbook'>query cookbook</a> to learn more.</p>
355
+
356
+ <h2>One JS framework is not enough!</h2>
357
+
358
+ <p>To flex our new BigQuery muscle let's find pages which use multiple JavaScript frameworks on same page:</p>
359
+
360
+ <div class='highlight'><pre><code class='sql'><span class='k'>SELECT</span> <span class='n'>pages</span><span class='p'>.</span><span class='n'>pageid</span><span class='p'>,</span> <span class='n'>url</span><span class='p'>,</span> <span class='n'>cnt</span><span class='p'>,</span> <span class='n'>libs</span><span class='p'>,</span> <span class='n'>pages</span><span class='p'>.</span><span class='n'>rank</span> <span class='n'>rank</span> <span class='k'>FROM</span> <span class='p'>[</span><span class='n'>httparchive</span><span class='p'>:</span><span class='n'>runs</span><span class='p'>.</span><span class='mi'>2013</span><span class='n'>_06_01_pages</span><span class='p'>]</span> <span class='k'>as</span> <span class='n'>pages</span> <span class='k'>JOIN</span> <span class='p'>(</span>
361
+ <span class='k'>SELECT</span> <span class='n'>pageid</span><span class='p'>,</span> <span class='k'>count</span><span class='p'>(</span><span class='k'>distinct</span><span class='p'>(</span><span class='k'>type</span><span class='p'>))</span> <span class='n'>cnt</span><span class='p'>,</span> <span class='n'>GROUP_CONCAT</span><span class='p'>(</span><span class='k'>type</span><span class='p'>)</span> <span class='n'>libs</span> <span class='k'>FROM</span> <span class='p'>(</span>
362
+ <span class='k'>SELECT</span> <span class='n'>REGEXP_EXTRACT</span><span class='p'>(</span><span class='n'>url</span><span class='p'>,</span>
363
+ <span class='n'>r</span><span class='s1'>'(jquery|dojo|angular|prototype|backbone|emberjs|sencha|scriptaculous).*\.js'</span><span class='p'>)</span> <span class='k'>type</span><span class='p'>,</span> <span class='n'>pageid</span>
364
+ <span class='k'>FROM</span> <span class='p'>[</span><span class='n'>httparchive</span><span class='p'>:</span><span class='n'>runs</span><span class='p'>.</span><span class='mi'>2013</span><span class='n'>_06_01_requests</span><span class='p'>]</span>
365
+ <span class='k'>WHERE</span> <span class='n'>REGEXP_MATCH</span><span class='p'>(</span><span class='n'>url</span><span class='p'>,</span> <span class='n'>r</span><span class='s1'>'jquery|dojo|angular|prototype|backbone|emberjs|sencha|scriptaculous.*\.js'</span><span class='p'>)</span>
366
+ <span class='k'>GROUP</span> <span class='k'>BY</span> <span class='n'>pageid</span><span class='p'>,</span> <span class='k'>type</span>
367
+ <span class='p'>)</span>
368
+ <span class='k'>GROUP</span> <span class='k'>BY</span> <span class='n'>pageid</span>
369
+ <span class='k'>HAVING</span> <span class='n'>cnt</span> <span class='o'>&gt;=</span> <span class='mi'>2</span>
370
+ <span class='p'>)</span> <span class='k'>as</span> <span class='n'>lib</span> <span class='k'>ON</span> <span class='n'>lib</span><span class='p'>.</span><span class='n'>pageid</span> <span class='o'>=</span> <span class='n'>pages</span><span class='p'>.</span><span class='n'>pageid</span>
371
+ <span class='k'>WHERE</span> <span class='n'>rank</span> <span class='k'>IS</span> <span class='k'>NOT</span> <span class='k'>NULL</span>
372
+ <span class='k'>ORDER</span> <span class='k'>BY</span> <span class='n'>rank</span> <span class='k'>asc</span>
373
+ </code></pre></div>
374
+
375
+
376
+ <p><img class='center' src='http://www.igvita.com/posts/13/ha-js-frameworks.png' style='width: 100%;'/></p>
377
+
378
+ <p>JQuery is the clear crowd favorite, but prototype (despite its age) is holding strong. Worse, there are many sites with three or four different frameworks, and even different versions of each one on the same page!</p>
379
+
380
+ <p>Happy <a href='http://research.google.com/pubs/pub36632.html'>dremeling</a> - err, <em>BigQuerying!</em> For more examples, check out this <a href='https://gist.github.com/igrigorik/5801492'>gist with sample queries</a>.</p>
381
+ <div class='feedflare'>
382
+ <a href='http://feeds.feedburner.com/~ff/igvita?a=uDo94--3uRw%3Aj89psqWqhRc%3AyIl2AUoC8zA'><img src='http://feeds.feedburner.com/~ff/igvita?d=yIl2AUoC8zA' border='0'/></a>
383
+ </div><img src='http://feeds.feedburner.com/~r/igvita/~4/uDo94--3uRw' height='1' width='1'/></p>
384
+ </div>
385
+
386
+
387
+
388
+
389
+ <div class="star-post">
390
+
391
+ <h2>
392
+
393
+ <img src="/images/theme/star.png"/>
394
+
395
+ <a href="http://blog.peepcode.com/blog/2013/elixir-is-for-programmers">Elixir is for programmers</a>
396
+ </h2>
397
+ <span class="small-text">Posted 6 days back at <a href="http://nubyonrails.topfunky.com/">Nuby on Rails</a></span>
398
+ <p><p><strong>This article is heavily styled and is best viewed at <a href='http://blog.peepcode.com/blog/2013/elixir-is-for-programmers'>PeepCode</a>!</strong></p><div id='attribution'>
399
+ <div class='row'>
400
+ <div class='column'>
401
+ <p>words and design Geoffrey Grosenbach<br/>
402
+ photography Paula Lavalle</p>
403
+ </div>
404
+ </div>
405
+ </div>
406
+ <div id='intro'>
407
+ <div class='row'>
408
+ <div class='column'>
409
+ <p>The early 2000’s were an exciting time for dynamic programming languages.</p>
410
+ <p>Excitement was high for the upcoming Perl 6. It ran on a brand new VM built specifically for dynamic languages and included dozens of experimental syntax sugars such as the <a href='http://perl6.wikia.com/wiki/Hyper_operator'>hyper operator</a>, which could run a calculation on every element of an array (somewhat like <code>map</code>). I attended the Seattle Perl User Group every month where you couldn’t ignore the anticipation!</p>
411
+ <p>It was during these years that I first heard about a weird language that used indentation to define scope (now known as Python). And on January 1, 2001, Dr. Dobb’s journal published an <a href='http://www.drdobbs.com/web-development/programming-in-ruby/184404436'>article</a> by Dave Thomas introducing Ruby to the West.</p>
412
+ <p>That’s not even counting the other languages I tried out for a few weeks each such as <a href='http://www.rebol.com/'><span class='caps'>REBOL</span></a>, RealBasic, and AppleScript.</p>
413
+ <p>There must be something special about the start of a decade, because I’m feeling that same kind of excitement and seeing that same kind of experimentation again. At the beginning of May we filmed a <a href='https://peepcode.com/products/elixir'>2 hour video</a> with Elixir creator José Valim. Elixir is a language that runs on the Erlang VM but is inspired by the syntax and concepts of many other languages including Ruby, Python, and even Lisp.</p>
414
+ <p>It’s not just a transpiler like CoffeeScript; it makes real Erlang <code>.beam</code> bytecode. According to <a href='http://devintorr.es/blog/2013/06/11/elixir-its-not-about-syntax/'>some</a>, parts of Elixir are even more optimized than Erlang itself. It benefits from all the concurrency and deployment options available to Erlang programs. Elixir can call Erlang functions and vice versa.</p>
415
+ <p>I don’t pretend to be an Elixir expert (that’s why we worked with José, who is), but I left the session with a lot of enthusiasm for Elixir’s design and features. Here are a few of them.</p>
416
+ </div>
417
+ </div>
418
+ </div>
419
+ <div class='implement'>
420
+ <div class='row'>
421
+ <div class='column'>
422
+ <h2>Smart <code>assert</code></h2>
423
+ <p>A programming language like Ruby loses a lot of data when you run it. It quickly loses access to the original source code. If you write a test with Ruby’s basic <code>assert</code>, it can only tell you that the test passed or that it didn’t; it can’t tell you why. Projects like <a href='https://github.com/seattlerb/ruby2ruby'>ruby2ruby</a> have tried to bridge this gap but haven’t had support from the core team.</p>
424
+ <p>Elixir works directly with your source code to do smart things. Tests rarely need more than the built-in <code>assert</code>, yet meaningful errors can be displayed. Take this Elixir code:</p>
425
+ <div class='highlight'><pre><span class='n'>test</span> <span class='s2'>"makes bacon"</span> <span class='k'>do</span>
426
+ <span class='k'> </span><span class='n'>assert</span> <span class='no'>Bacon</span><span class='o'>.</span><span class='n'>make_bacon</span><span class='p'>()</span> <span class='o'>==</span> <span class='s2'>"avocado"</span>
427
+ <span class='k'>end</span></pre></div>
428
+ <p>By reading it, we can see that it’s erroneously making <code>bacon</code> but looking for <code>"avocado"</code>. We expect that it will fail. If this were a test in Ruby (or any other language), we would see an error such as <code>expected true, got false</code>. Not too helpful.</p>
429
+ <p>In Elixir, we see this:</p>
430
+ <div class='highlight'><pre>** (ExUnit.ExpectationError)
431
+ expected: "bacon"
432
+ to be equal to (==): "avocado"
433
+ at test/bacon_test.exs:14</pre></div>
434
+ <p>Elixir knows that <code>==</code> is being used in the assertion, and shows you the values on either side of <code>==</code> when the test fails. Now that’s a useful error!</p>
435
+ <h2>Multi-block control flow</h2>
436
+ <p>For years I’ve wanted to be able to write my own control flow structures, such as an <code>each...else</code> that runs an <code>else</code> block if the <code>each</code> is empty (<a href='http://handlebarsjs.com/#iteration'>Handlebars</a> templates have this).</p>
437
+ <p>The only way to do that in Ruby would be to pass several lambdas to a method, which would be ugly.</p>
438
+ <p>In Elixir, the relationship between single line functions and multi-line blocks is well thought out.</p>
439
+ <p>These two are equivalent:</p>
440
+ <div class='highlight'><pre><span class='c1'># Single line</span>
441
+ <span class='k'>if</span><span class='p'>(</span><span class='n'>condition</span><span class='p'>,</span> <span class='k'>do</span><span class='p'>:</span> <span class='n'>a</span><span class='p'>,</span> <span class='k'>else</span><span class='p'>:</span> <span class='n'>b</span><span class='p'>)</span>
442
+
443
+ <span class='c1'># Multiple lines</span>
444
+ <span class='k'>if</span> <span class='n'>condition</span> <span class='k'>do</span>
445
+ <span class='k'> </span><span class='n'>a</span>
446
+ <span class='k'>else</span>
447
+ <span class='n'>b</span>
448
+ <span class='k'>end</span></pre></div>
449
+ <p>In the single line version, <code>if</code> is a function that takes two arguments: the <code>condition</code> and the <code>clauses</code>. The <code>clauses</code> are <code>do</code> and <code>else</code>.</p>
450
+ <p>The multi-line version needs no explanation.</p>
451
+ <p>But the fact that these two are equivalent means you can write a macro that works just like a built-in. Because that’s how the built-ins are written, too! (<a href='https://github.com/elixir-lang/elixir/blob/c572cb80fced4111ea98ed4a0e27550e09816f66/lib/elixir/lib/kernel.ex#L2526'>source</a>)</p>
452
+ <h2>Consistent use of <code>do</code></h2>
453
+ <p>Developers who love Ruby like the fact that they can override built-in operators and write DSLs that look like built-in Ruby syntax.</p>
454
+ <p>But many of Ruby’s syntactical elements are off limits. You can’t write Ruby code that works like a <code>class</code> definition, or an <code>if</code>, or a <code>case...when</code>. Why? <code>class</code> has an <code>end</code>, but no <code>do</code>. There’s no way to write a custom method that takes a block without <code>do</code>.</p>
455
+ <p>Elixir is consistent.</p>
456
+ <p>Need a module? It’s <code>defmodule...do</code>. Need an <code>if</code>? It also uses <code>do</code>. Same with <code>def</code>.</p>
457
+ <div class='highlight'><pre><span class='k'>defmodule</span> <span class='no'>MyModule</span> <span class='k'>do</span>
458
+ <span class='k'> def</span> <span class='n'>my_function</span> <span class='k'>do</span>
459
+ <span class='k'> </span>
460
+ <span class='k'> end</span>
461
+ <span class='k'>end</span></pre></div>
462
+ <p>If you want to write a macro that works like the language does, you can. Because Elixir is implemented with the same tools available for you to use.</p>
463
+ <h2>Built-in <span class='caps'>TDD</span></h2>
464
+ <p>I find it extremely difficult to learn a new language if I can’t write unit tests. My confidence in writing JavaScript and many other languages went way up once I started using a decent test runner.</p>
465
+ <p>With Elixir, it’s built in. Use the <code>mix</code> command to generate a <code>new</code> app and you’re ready to go with a unit test. Run <code>mix test</code> to run the test suite. Done.</p>
466
+ <p>It even has conveniences like a <code>test</code> function that takes a quoted descriptive message as the name of the test.</p>
467
+ <div class='highlight'><pre><span class='n'>test</span> <span class='s2'>"extracts m3u8 from index file"</span> <span class='k'>do</span>
468
+ <span class='k'> </span><span class='n'>m3u8s</span> <span class='o'>=</span> <span class='no'>Streamers</span><span class='o'>.</span><span class='n'>extract_m3u8</span> <span class='n'>index_file</span>
469
+ <span class='n'>assert</span> <span class='no'>Enum</span><span class='o'>.</span><span class='n'>first</span><span class='p'>(</span><span class='n'>m3u8s</span><span class='p'>)</span> <span class='o'>==</span> <span class='no'>Streamers</span><span class='o'>.</span><span class='no'>M3U8</span><span class='p'>[</span><span class='ss'>program_id:</span> <span class='m'>1</span><span class='p'>,</span> <span class='ss'>bandwidth:</span> <span class='m'>110000</span><span class='p'>,</span> <span class='ss'>path:</span> <span class='n'>m3u8_sample</span><span class='p'>]</span>
470
+ <span class='n'>assert</span> <span class='n'>length</span><span class='p'>(</span><span class='n'>m3u8s</span><span class='p'>)</span> <span class='o'>==</span> <span class='m'>5</span>
471
+ <span class='k'>end</span></pre></div>
472
+ <p>And it can run your tests concurrently with a single <code>async</code> option (<a href='http://elixir-lang.org/getting_started/ex_unit/1.html'>docs</a>).</p>
473
+ <h2>Mind-blowing metaprogramming: <code>upcase</code></h2>
474
+ <p>One of the most ingenious techniques that José mentioned didn’t make it into the final cut of our video.</p>
475
+ <p>To capitalize a word, Elixir could implement a single <code>upcase</code> function that keeps a list of Unicode letters in memory and figures out how to translate between them.</p>
476
+ <p>Instead, it generates a function definition for each letter. They look roughly like this (<a href='https://github.com/elixir-lang/elixir/blob/b535f0746e9a0d198033509c19457a5182af2102/lib/elixir/priv/unicode.ex#L78'>source</a>):</p>
477
+ <div class='highlight'><pre><span class='k'>def</span> <span class='n'>upcase</span><span class='p'>(</span><span class='s2'>"é"</span> <span class='o'>&lt;&gt;</span> <span class='n'>rest</span><span class='p'>)</span> <span class='k'>do</span>
478
+ <span class='k'> </span><span class='p'>[</span><span class='s2'>"É"</span><span class='p'>]</span> <span class='o'>++</span> <span class='n'>upcase</span><span class='p'>(</span><span class='n'>rest</span><span class='p'>)</span>
479
+ <span class='k'>end</span></pre></div>
480
+ <p>A few things are going on here. Elixir can match functions on the number, type, and <em>content</em> of its arguments. So it looks for a letter such as <code>é</code>. It knows the upper case version of the letter, then sends the rest of the string to the next letter’s <code>upcase</code> function.</p>
481
+ <p>Pretty cool!</p>
482
+ <h2>Conclusion</h2>
483
+ <p>Elixir has many of the features that I look for in a programming language. Its authors have stolen useful features from other languages, it focuses on making it easier to write complex applications, and it has a healthy balance between performance and syntax.</p>
484
+ <p>Elixir isn’t the only way to write concurrent applications, but it’s definitely one I’ll be experimenting with for a few months. If you want to learn what it’s about, check out our fast-paced two hour video at PeepCode:
485
+ <a href='https://peepcode.com/products/elixir'><img src='https://peepcode.com/system/uploads/2013/peepcode-elixir-cover-sale.png' alt=''/></a></p>
486
+ </div>
487
+ </div>
488
+ </div></p>
489
+ </div>
490
+
491
+
492
+ <br />
493
+ <p align="right"><div class="pagination"><span class="disabled prev_page">&laquo; Previous</span> <span class="current">1</span> <a href="/2" rel="next">2</a> <a href="/3">3</a> <a href="/4">4</a> <a href="/5">5</a> <a href="/6">6</a> <a href="/7">7</a> <a href="/8">8</a> <a href="/9">9</a> <span class="gap">&hellip;</span> <a href="/597">597</a> <a href="/598">598</a> <a href="/2" class="next_page" rel="next">Next &raquo;</a></div></p>
494
+
495
+
496
+
497
+ </div>
498
+
499
+ </div>
500
+ <div class="footer">
501
+ <br />
502
+ &copy; The contents of this website are copyrighted by respective blog owners.
503
+ <br /><br />
504
+ Designed and developed by <a href="http://m.onkey.org">Pratik</a> and <a href="http://anup.info">Anup</a>
505
+ </div>
506
+ </div>
507
+ <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
508
+ </script>
509
+ <script type="text/javascript">
510
+ _uacct = "UA-929590-1";
511
+ urchinTracker();
512
+ </script>
513
+ </body>
514
+ </html>
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Planetruby2feed do
4
+ it "sets the @@planet class variable" do
5
+ planet = Planetruby2feed::Base.run!
6
+ expect(planet).to be_an_instance_of(Planetruby2feed::Base)
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Planetruby2feed do
4
+ it "finds the planetrubyonrails.org website" do
5
+ planet = Planetruby2feed::Base.run!
6
+ expect(planet.webpage).to be_an_instance_of(Nokogiri::HTML::Document)
7
+ end
8
+
9
+ # it "manage problems while getting the website" do
10
+ # stub_const("Planetruby2feed::URL", "http://xxx.asda.com")
11
+ # logger = double("logger")
12
+
13
+ # planet = Planetruby2feed::Base.run!
14
+ # planet.logger = logger
15
+
16
+ # planet.logger.should_receive(:fatal).with /\[ERROR\].*/
17
+ # end
18
+
19
+ it "finds the posts in the HTML code" do
20
+ planet = Planetruby2feed::Base.run!
21
+ expect(planet.posts.size).to be > 0
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: planetruby2feed
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tommaso Visconti
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: nokogiri
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sinatra
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: builder
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Transform planetrubyonrails.com to RSS feed
112
+ email:
113
+ - tommaso.visconti@gmail.com
114
+ executables:
115
+ - planetruby2feed
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - .gitignore
120
+ - .rspec
121
+ - Gemfile
122
+ - LICENSE.txt
123
+ - README.md
124
+ - Rakefile
125
+ - bin/planetruby2feed
126
+ - lib/planetruby2feed.rb
127
+ - lib/planetruby2feed/constants.rb
128
+ - lib/planetruby2feed/parser.rb
129
+ - lib/planetruby2feed/scraper.rb
130
+ - lib/planetruby2feed/version.rb
131
+ - lib/planetruby2feed/webserver.rb
132
+ - planetruby2feed.gemspec
133
+ - resources/views/rss.builder
134
+ - spec/spec_helper.rb
135
+ - spec/support/www.planetrubyonrails.com.html
136
+ - spec/unit/base_spec.rb
137
+ - spec/unit/scraper_spec.rb
138
+ homepage: https://bitbucket.org/tommyblue/planetruby2feed
139
+ licenses:
140
+ - MIT
141
+ metadata: {}
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - '>='
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubyforge_project:
158
+ rubygems_version: 2.0.2
159
+ signing_key:
160
+ specification_version: 4
161
+ summary: Creates a RSS feed reading entries from planetrubyonrails.com
162
+ test_files:
163
+ - spec/spec_helper.rb
164
+ - spec/support/www.planetrubyonrails.com.html
165
+ - spec/unit/base_spec.rb
166
+ - spec/unit/scraper_spec.rb