Showing posts with label Ruby. Show all posts
Showing posts with label Ruby. Show all posts
Sunday, June 23, 2013
Writing simple ruby utilities for Google IMAP + OAuth 2.0
(blogarhythm ~ Unpretty/Fanmail: TLC)
There are some good ruby gems available for dealing with OAuth 2.0 and talking to Google APIs, for example:
- google-api-client is the official Google API Ruby Client makes it trivial to discover and access supported APIs.
- oauth2-client provides generic OAuth 2.0 support that works not just with Google
- gmail_xoauth implements XAUTH2 for use with Ruby Net::IMAP and Net::SMTP
- gmail provides a rich Ruby-esque interface to GMail but you need to pair it with gmail_xoauth for OAuth 2 support (also seems that it's in need of a new release to merge in various updates and extensions people have been working on)
For the task I had at hand, I just wanted something simple: connect to a mailbox, look for certain messages, download and do something with the attachments and exit. It was going to be a simple utility to put on a cron job.
No big deal. The first version simple used gmail_xoauth to enable OAuth 2.0 support for IMAP, and I added some supporting routines to handle access_token refreshing.
It worked fine as a quick and dirty solution, but had a few code smells. Firstly, too much plumbing code. But most heinously - you might seen this yourself if you've done any client utilities with OAuth - it used the widely-recommended oauth2.py Python script to orchestrate the initial authorization. For a ruby tool!
Enter the GmailCli gem
So I refactored the plumbing into a new gem called gmail_cli and it is intended for one thing: a super-simple way to whip up utilities that talk to Google IMAP and providing all the OAuth 2.0 support you need. It actually uses google-api-client and gmail_xoauth under the covers for the heavy lifting, but wraps them up in a neat package with the simplest interface possible. Feel free to go use and fork it!With gmail_cli in your project, there are just 3 things to do:
- If you haven't already, create your API project credentials in the Google APIs console (on the "API Access" tab)
- Use the built-in rake task or command-line to do the initial authorization. You would normally need to do this only once for each deployment:
$ rake gmail_cli:authorize client_id='id' client_secret='secret' $ gmail_cli authorize --client_id 'id' --client_secret 'secret'
- Use the access and refresh tokens generated in step 2 to get an IMAP connection in your code. This interface takes care of refreshing the access token for you as required each time you use it:
# how you store or set the credentials Hash is up to you, but it should have the following keys: credentials = { client_id: 'xxxx', client_secret: 'yyyy', access_token: 'aaaa', refresh_token: 'rrrr', username: 'name@gmail.com' } imap = GmailCli.imap_connection(credentials)
A Better Way?
Polling a mailbox is a terrible thing to have to do, but sometimes network restrictions or the architecture of your solution makes it the best viable option. Much better is to be reactive to mail that gets pushed to you as it is delivered.I've written before about Mandrill, which is the transactional email service from the same folks who do MailChimp. I kinda love it;-) It is perfect if you want to get inbound mail pushed to your application instead of polling for it. And if you run Rails, I really would encourage you to checkout the mandrill-rails gem - it adds Mandrill inbound mail processing to my Rails apps with just a couple of lines of code.
(追記) (追記ここまで)
Tuesday, June 18, 2013
Ruby Tuesday
(blogarhythm ~ Ruby - Kaiser Chiefs)
@a_matsuda convinced us to dive into Ruby 2.0 at RedDotRubyConf, so I guess this must be the perfect day of the week for it!
Ruby 2.0.0 is currently at p195, and we heard at the conference how stable and compatible it is.
One change we learned that may catch us if we do much multilingual work that's not already unicode is the change that Ruby now assumes UTF-8 encoding for source files. So the special "encoding: utf-8" marker becomes redundant, but if we don't include it the behaviour in 2.0.0 can differ from earlier versions:
I already have OpenSSL 1.0.1c installed using brew (so it doesn't mess with the MacOSX system-installed OpenSSL), so updating is simply:
@a_matsuda convinced us to dive into Ruby 2.0 at RedDotRubyConf, so I guess this must be the perfect day of the week for it!
Ruby 2.0.0 is currently at p195, and we heard at the conference how stable and compatible it is.
One change we learned that may catch us if we do much multilingual work that's not already unicode is the change that Ruby now assumes UTF-8 encoding for source files. So the special "encoding: utf-8" marker becomes redundant, but if we don't include it the behaviour in 2.0.0 can differ from earlier versions:
$ cat encoding_binary.rb
s = "\xE3\x81\x82"
p str: s, size: s.size
$ ruby -v encoding_binary.rb
ruby 2.0.0p195 (2013年05月14日 revision 40734) [x86_64-darwin11.4.2]
{:str=>"あ", :size=>1}
$ ruby -v encoding_binary.rb
ruby 1.9.3p429 (2013年05月15日 revision 40747) [x86_64-darwin11.4.2]
{:str=>"\xE3\x81\x82", :size=>3}
Quickstart on MacOSX with RVM
I use rvm to help manage various Ruby installs on my Mac, and trying out new releases is exactly the time you want it's assistance to prevent screwing up your machine. There were only two main things I needed to take care of to get Ruby 2 installed and running smoothly:- Update rvm so it knows about the latest Ruby releases
- Update my OpenSSL installation (it seems 1.0.1e is required although I haven't found that specifically documented anywhere)
$ rvm get stable # => updated ok $ rvm install ruby-2.0.0 Searching for binary rubies, this might take some time. No binary rubies available for: osx/10.7/x86_64/ruby-2.0.0-p195. Continuing with compilation. Please read 'rvm mount' to get more information on binary rubies. Installing requirements for osx, might require sudo password. -bash: /usr/local/Cellar/openssl/1.0.1e/bin/openssl: No such file or directory Updating certificates in ''. mkdir: : No such file or directory Password: mkdir: : No such file or directory Can not create directory '' for certificates.Not good!!! What's all that about? Turns out to be just a very clumsy way of telling me I don't have OpenSSL 1.0.1e installed.
I already have OpenSSL 1.0.1c installed using brew (so it doesn't mess with the MacOSX system-installed OpenSSL), so updating is simply:
$ brew upgrade openssl ==> Summary /usr/local/Cellar/openssl/1.0.1e: 429 files, 15M, built in 5.0 minutesSo then I can try the Ruby 2 install again, starting with the "rvm requirements" command to first make sure all pre-requisites are installed:
$ rvm requirements Installing requirements for osx, might require sudo password. [...] Tapped 41 formula Installing required packages: apple-gcc42................. Updating certificates in '/usr/local/etc/openssl/cert.pem'. $ rvm install ruby-2.0.0 Searching for binary rubies, this might take some time. No binary rubies available for: osx/10.7/x86_64/ruby-2.0.0-p195. Continuing with compilation. Please read 'rvm mount' to get more information on binary rubies. Installing requirements for osx, might require sudo password. Certificates in '/usr/local/etc/openssl/cert.pem' already are up to date. Installing Ruby from source to: /Users/paulgallagher/.rvm/rubies/ruby-2.0.0-p195, this may take a while depending on your cpu(s) [...] $OK, this time it installed cleanly as I can quickly verify:
$ rvm use ruby-2.0.0 $ ruby -v ruby 2.0.0p195 (2013年05月14日 revision 40734) [x86_64-darwin11.4.2] $ irb -r openssl 2.0.0p195 :001> OpenSSL::VERSION => "1.1.0" 2.0.0p195 :002> OpenSSL::OPENSSL_VERSION => "OpenSSL 1.0.1e 11 Feb 2013"
(追記) (追記ここまで)
Saturday, June 15, 2013
Optimising presence in Rails with PostgreSQL
(blogarhythm ~ Can't Happen Here - Rainbow)
It is a pretty common pattern to branch depending on whether a query returns any data - for example to render a quite different view. In Rails we might do something like this:
But when we are running on PostgreSQL in particular, we've learned to be leery of COUNT(*) due to it's well known performance problems. In fact I first started digging into this question when I started seeing expensive COUNT(*) queries show up in NewRelic slow transaction traces. How expensive COUNT(*) actually is depends on many factors including the complexity of the query, availability of indexes, size of the table, and size of the results set.
So can we improve things by avoiding the COUNT(*) query? Assuming we are going to use all the results anyway, and we haven't injected any calculated columns in the query, we could simply to_a the query before testing presence i.e.:
I ran some benchmarks comparing the two approaches with different kinds of queries on a pretty well-tuned system and here are some of the results:
Clearly, depending on the type of query we can gain up to 40% performance improvement by restructuring our code a little. While my aggregate results were fairly consistent over many runs, the performance of individual queries did vary quite widely.
I should note that the numbers were *not* consistent or proportional across development, staging, test and production environments (mainly due to differences in data volumes, latent activity and hardware) - so you can't benchmark on development and assume the same applies in production.
It is a pretty common pattern to branch depending on whether a query returns any data - for example to render a quite different view. In Rails we might do something like this:
query = User.where(deleted_at: nil).and_maybe_some_other_scopes
if results = query.presence
results.each {|row| ... }
else
# do something else
endWhen this code executes, we raise at least 2 database requests: one to check presence, and another to retrieve the data. Running this at the Rails console, we can see the queries logged as they execute, for example: (0.9ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL User Load (15.2ms) SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULLThis is not surprising since under the covers, presence (or present?) end up calling count which must do the database query (unless you have already accessed/loaded the results set). And 0.9ms doesn't seem too high a price to pay to determine if you should even try to load the data, does it?
But when we are running on PostgreSQL in particular, we've learned to be leery of COUNT(*) due to it's well known performance problems. In fact I first started digging into this question when I started seeing expensive COUNT(*) queries show up in NewRelic slow transaction traces. How expensive COUNT(*) actually is depends on many factors including the complexity of the query, availability of indexes, size of the table, and size of the results set.
So can we improve things by avoiding the COUNT(*) query? Assuming we are going to use all the results anyway, and we haven't injected any calculated columns in the query, we could simply to_a the query before testing presence i.e.:
query = User.where(deleted_at: nil).and_maybe_some_other_scopes
if results = query.to_a.presence
results.each {|row| ... }
else
# do something else
endI ran some benchmarks comparing the two approaches with different kinds of queries on a pretty well-tuned system and here are some of the results:
| Query | Using present? | Using to_a | Faster By |
|---|---|---|---|
| 10k indexed queries returning 1 / 1716 rows | 17.511s | 10.938s | 38% |
| 4k complex un-indexed queries returning 12 / 1716 rows | 23.603s | 15.221s | 36% |
| 4k indexed queries returning 1 / 1763218 rows | 22.943s | 20.924s | 9% |
| 10 complex un-indexed queries returning 15 / 1763218 rows | 23.196s | 14.072s | 40% |
Clearly, depending on the type of query we can gain up to 40% performance improvement by restructuring our code a little. While my aggregate results were fairly consistent over many runs, the performance of individual queries did vary quite widely.
I should note that the numbers were *not* consistent or proportional across development, staging, test and production environments (mainly due to differences in data volumes, latent activity and hardware) - so you can't benchmark on development and assume the same applies in production.
Things get murky with ActiveRecord add-ons
So far we've talked about the standard ActiveRecord situation. But there are various gems we might also be using to add features like pagination and search magic. MetaSearch is an example: a pretty awesome gem for building complex and flexible search features. But (at least with version 1.1.3) present? has a little surprise in store for you:irb> User.where(id: '0').class => ActiveRecord::Relation irb> User.where(id: 0).present? (0.8ms) SELECT COUNT(*) FROM "users" WHERE "users"."id" = 0 => false irb> User.search(id_eq: 0).class => MetaSearch::Searches::User irb> User.search(id_eq: 0).present? => true
Any Guidelines?
So, always to_a my query results? Well, no, it's not that simple. Here are some things to consider:- First, don't assume that <my_scoped_query>.present? means what you think it might mean - test or play it safe
- If you are going to need all result rows anyway, consider calling to_a or similar before testing presence
- Avoid this kind of optimisation except at the point of use. One of the beauties of ActiveRecord::Relation is the chainability - something we'll kill as soon as we hydrate to a result set Array for example.
- While I got a nice 40% performance bonus in some cases with a minor code fiddle, mileage varies and much depends on the actual query. You probably want to benchmark in the actual environment that matters and not make any assumptions.
(追記) (追記ここまで)
Sunday, June 09, 2013
My Virtual Swag from #rdrc
(blogarhythm ~ Everybody's Everything - Santana)
So the best swag you can get from a technology conference is code, right? Well RedDotRubyConf 2013 did not disappoint! Thanks to some fantastic speakers, my weekends for months to come are spoken for. Here's just some of the goodness:
So the best swag you can get from a technology conference is code, right? Well RedDotRubyConf 2013 did not disappoint! Thanks to some fantastic speakers, my weekends for months to come are spoken for. Here's just some of the goodness:
- First up, @tenderlove kicked off an #irresponsibleruby meme with some crazy internal fiddles.
- From @gazay: gon is a gem that makes it easy to expose server data to javascript.
- From @flyerhzm and others: convinced me to go try Celluloid and Celluloid::IO for building actor-based asynchronous systems.
- From @zacksiri: transponder an opinionated javascript library for assisting in working with front-end heavy rails app.
- From @netzke: checkout netzke for building complex UIs on Rails with Ext JS.
- From @jimweirich: equator_weight.rb so @tenderlove knows how much more he can eat while in Singapore;-)
- From @dqminh: The RSpec applause_formatter.rb so you too can get applause when your tests go green, just like @jimweirich.
- From @josevalim: awesome talk on concurrency and a tip to checkout thread_safe. And somehow I now have an urge to go play with Elixir too;-)
- From @sausheong: tanks and tanksworld demonstrating Gosu-based games.
- From @sikachu: appraisal for testing against multiple permutations of gem dependencies.
- @a_matsuda convinced us to use Ruby 2.0, spam his friends in Japan on twitter, and blow our minds with Trick 2013 ruby code.
- From @nigelr: fracture an interesting way of co-ordinating expectations for multiple test conditions to things don't fall through the cracks.
- From @steveklabnik: Shoes and Functional Reactive Programming in Ruby with frappuccino. wtf!
- And just for completeness, from @tardate (me): RGovData, sps_bill_scanner, and megar.
Will I still be a Rubyist in 5 years? #rdrc
(blogarhythm ~ Ruby - Kaiser Chiefs)
The third RedDotRubyConf is over, and I think it just keeps getting better! Met lots of great people, and saw so many of my Ruby heroes speak on stage. Only thing that could make it even better next year would be to get the video recording thing happening!
I had the humbling opportunity to share the stage and here are my slides. Turned out to be a reflection on whether I'd still be a Rubyist in another 5 years, and what are the external trends that might change that. Short story: Yes! Of course. I'll always think like a Rubyist even though things will probably get more polyglot. The arena of web development is perhaps the most unpredictable though.
A couple of areas I highlight that really need a bit more love include:
I mentioned a few of my projects in passing. Here are the links for convenience:
[フレーム]
The third RedDotRubyConf is over, and I think it just keeps getting better! Met lots of great people, and saw so many of my Ruby heroes speak on stage. Only thing that could make it even better next year would be to get the video recording thing happening!
I had the humbling opportunity to share the stage and here are my slides. Turned out to be a reflection on whether I'd still be a Rubyist in another 5 years, and what are the external trends that might change that. Short story: Yes! Of course. I'll always think like a Rubyist even though things will probably get more polyglot. The arena of web development is perhaps the most unpredictable though.
A couple of areas I highlight that really need a bit more love include:
- There's a push on SciRuby. Analytics are no longer the esoteric domain of bioinformaticists. Coupled with Big Data (which Ruby is pretty good at), analytics are driving much of the significant innovation in things we build.
- Krypt - an effort lead by Martin Boßlet to improve the cryptographic support in Ruby. My experience building megar made it painfully obvious why we need to fix this.
Let it never be said, the romance is dead
'Cos there’s so little else occupying my head
I mentioned a few of my projects in passing. Here are the links for convenience:
- RGovData is a ruby library for really simple access to government data. It aims to make consuming government data sets a "one liner", letting you focus on what you are trying to achieve with the data, and happily ignore all the messy underlying details of transport protocols, authentication and so on.
- sps_bill_scanner is a ruby gem for converting SP Services PDF invoices into data that can be analysed with R. Only useful if you are an SP Services subscriber in Singapore, but other wise perhaps an interesting example of extracting postitional text from PDF and doing some R.
- megar ("megaargh!" in pirate-speak) is a Ruby wrapper and command-line (CLI) client for the mega.co.nz API. My example of how you *can* do funky crypto in Ruby ... it's just much harder than it should be!
[フレーム]
Sunday, March 10, 2013
Rolling the Mega API with Ruby
(blogarhythm ~ Can you keep a secret? - 宇多田ヒカル)
Megar (“megaargh!” in pirate-speak) is a Ruby wrapper and command-line client for the Mega API.
In the current release (gem version 0.0.3), it has coverage of the basic file/folder operations: connect, get file/folder listings and details, upload and download files. You can use it directly in Ruby with what I hope you'll find is a very sane API, but it also sports a basic command-line mode for simple listing, upload and download tasks.
If you are interested in hacking around with Mega, and prefer to do it in Ruby, give it a go! Like this:
I was keen to get a Mega account and check it out when the launch publicity hit, and was immediately impressed by the web interface. Very slick. Notwithstanding some of the intense analysis and some criticism (for example by SpiderOak and Security Now), the "trust no-one" design approach is very interesting to contemplate and hack around with.
The Mega API is still evolving. The documentation is thin and the main resource we have to work with is the Javascript reference implementation that actually runs the Mega site. But there has been quite a bit of work in the community to hack on the API - particularly in Python (with API analysis and projects like mega.py).
It didn't take me long to realise there was nothing much going on with Ruby. After a bit of messing around, I think the main reason for that is the pretty wretched state of cryptographic support in Ruby. Unlike Python (which has PyCrypto amongst others I'm sure), in Ruby we still on the whole get by with thin wrappers on OpenSSL that look and smell distinctly C-dy. But that's a challenge for another day...
For now I'm pretty happy that Megar has all the main crypto challenges solved (after a bit of low-level reverse engineering supported by a healthy dose of TDD). Now I wonder what I'm going to use it for?
Megar (“megaargh!” in pirate-speak) is a Ruby wrapper and command-line client for the Mega API.
In the current release (gem version 0.0.3), it has coverage of the basic file/folder operations: connect, get file/folder listings and details, upload and download files. You can use it directly in Ruby with what I hope you'll find is a very sane API, but it also sports a basic command-line mode for simple listing, upload and download tasks.
If you are interested in hacking around with Mega, and prefer to do it in Ruby, give it a go! Like this:
# do a complete folder/file listing session = Megar::Session.new(email: 'my@email.com', password: 'my_password') session.folders.each do |folder| folder.files.each do |file| puts file.name end end # upload a file file_handle = '../my_files/was_called_this.mp3' session.files.create( name: 'First.mp3', body: file_handle )Or from the command line:
$ megar -e my@email.com -p my_password ls $ megar -e my@email.com -p my_password put *.pdfI would still call it "experimental" at this stage because it needs more widespread hammering, and of course the Mega API is not fully documented yet. There are many more features of the API that it would be good to support, and I'd love for others to pitch in and help - go fork it on github!
I was keen to get a Mega account and check it out when the launch publicity hit, and was immediately impressed by the web interface. Very slick. Notwithstanding some of the intense analysis and some criticism (for example by SpiderOak and Security Now), the "trust no-one" design approach is very interesting to contemplate and hack around with.
The Mega API is still evolving. The documentation is thin and the main resource we have to work with is the Javascript reference implementation that actually runs the Mega site. But there has been quite a bit of work in the community to hack on the API - particularly in Python (with API analysis and projects like mega.py).
It didn't take me long to realise there was nothing much going on with Ruby. After a bit of messing around, I think the main reason for that is the pretty wretched state of cryptographic support in Ruby. Unlike Python (which has PyCrypto amongst others I'm sure), in Ruby we still on the whole get by with thin wrappers on OpenSSL that look and smell distinctly C-dy. But that's a challenge for another day...
For now I'm pretty happy that Megar has all the main crypto challenges solved (after a bit of low-level reverse engineering supported by a healthy dose of TDD). Now I wonder what I'm going to use it for?
Saturday, October 13, 2012
The Full Monty - from Ruby to Python n00bie
It was a casual discussion about testing that re-ignited my interest in taking a peek over the fence. I picked up a copy of Greg L. Turnquist's Python Testing Cookbook and enjoyed playing around with a couple of the Python testing tools. It's an excellent book for ramping up your testing skills with Python - eminently clear and practical.
I was pretty sure that if any language community came close to matching Ruby's approach to development it would be Python. But is that true?
Most comparisons of Ruby and Python (like here, here and here) focus on language syntax and features. Conclusion?
same but different!What I find more interesting is a comparison of the fundamental productivity patterns used in each community, assuming your goal is to produce high-quality code that can be reliably distributed or deployed, and likely makes liberal use of other - probably open source - code components.
So here is a rundown for some of the common patterns I could not do without when developing in Ruby, and what appear to be the leading Python equivalents - according to my research as of Oct-2012, but I welcome corrections and further information from any Python experts out there!
Environment Partitioning
We don't like dependencies from other projects leaking over to contaminate and confound what we are trying to work on. While you could run up a separate VM for each project, it is much better if you have tools that can keep installed libraries and even the language distributions separate for each project.The Ruby Way: rvm is the leading tool for creating isolated ruby and gemset environments. A less intrusive alternative is rbenv (compared here).
The Python Way: virtualenv creates isolated Python environments. Ref: SO.
Dependency Management
It is likely our project will make use of other packages. We want automatic dependency management so that we can easy deploy predictable compositions of code packages.The Ruby Way: bundler
The Python Way: pip with a requirements.txt file. Ref: SO
Reusable Code Packaging
For anything more than trivial scripts, we probably want to package our project so that it can be reliably distributed or deployed.The Ruby Way: we use gems. Easily built by hand, or bootstrapped with a tool like bundler or jeweler
The Python Way: use setuptools (enhancements to the Python distutils) to build and distribute eggs. Ref: SO
Reusable Code Distribution
Both Ruby and Python are very open-source oriented programming communities. Not only do we consume a great deal, but it's likely we'll often want to make our own contributions easily available to others.The Ruby Way: RubyGems for distribution, with source code most often found on github.
The Python Way: pip. And source code also seems to be showing up more on github than historical use of svn repositories. Ref: quora
Project Build Tool
We'd prefer a common approach to running project build, doc, install and test tasks rather than rolling our own for each project.The Ruby Way: rake.
The Python Way: this one I'm not so sure of. It seems most projects simply provide a custom setup script using distutils, but there are a variety of projects that support more complex build requirements. Ref: SO
Automated Testing
It's 2012 already, we know that automated testing is a cornerstone of quality software. Especially so for code that is going to be widely shared and reused. Whether you do TDD, BDD or simply unit test, we all have a good test framework or two on our toolbelt.The Ruby Way: Test::Unit, RSpec, Cucumber amongst others. It is extremely rare to find a project these days that doesn't have tests of some flavour.
The Python Way: unittest (sometimes called PyUnit) and doctest are common frameworks for unit testing and TDD. nose is a test runner, especially good for non-trivial projects. Lettuce is the rough Python equivalent of Cucumber. Like Ruby, there are many other projects to assist testing such as mocking tools like Mockito.
Bonus: open source projects have been rapidly adopting Travis for automated continuous integration on the back of a github commit. And it works for Ruby and Python.
Blogarhythm: Always Look On The Bright Side Of Life - Eric Idle/Monty Python
Sunday, July 10, 2011
It goes PING!
If you're like me, you have a bunch of trusty (and rusty) shell scripts that you reach for when doing things like testing a new load balancer.
Enough of that! igp (It goes PING!) is a simple command line utility for testing services with a range of common protocols: ICMP, UDP, TCP, HTTP/S, LDAP/S and so on.
This is nothing earth shattering I know, but it's nice to have simple cross-platform (since it's ruby) tool that does all the common protocols in one. Thankfully, most of the work has already been done by the net-ping library - igp really just provides a sleek command-line wrapper.
The only dependency is ruby+rubygems. Just:
Blogarhythm: Keep it Up - Snap!
Enough of that! igp (It goes PING!) is a simple command line utility for testing services with a range of common protocols: ICMP, UDP, TCP, HTTP/S, LDAP/S and so on.
This is nothing earth shattering I know, but it's nice to have simple cross-platform (since it's ruby) tool that does all the common protocols in one. Thankfully, most of the work has already been done by the net-ping library - igp really just provides a sleek command-line wrapper.
The only dependency is ruby+rubygems. Just:
gem install igpAnd then you are ready to capture traces, for example:
igp my.server.com
# ^ ICMP assumed by default. This is the same as:
igp icmp://my.server.com
igp http://my.insecure.server.com
igp http://my.insecure.server-hiding-on-a-funny-port.com:8080/javascripts/all.js
igp https://my.secure.server.com
igp https://my.secure.server-hiding-on-a-funny-port.com:4443
igp tcp://my.tcp-service.com:9091
igp udp://my.udp-service.com:123
igp ldap://my.insecure.ldap.server.com
igp ldaps://my.secure.ldap.server.com
Blogarhythm: Keep it Up - Snap!
Sunday, January 30, 2011
Paranoid Yak Shaving
So a few weeks ago I found myself wanting "soft-delete" in a Rails app. Ruby Toolbox is a little long in the tooth on the subject, but after a little more research I discovered xpond's paranoid project that was just what I wanted:
All was cool, except at about the same time we updated to Rails 3.0.3 and it broke (as it turned out, due to changes in AREL 2.0.6 internals).
One of the beautiful things about github and the way it's been adopted by the ruby/rails community in particular is that it makes it so damn easy to just dive in and help update code originally contributed by other people. So paranoid needs updating for Rails 3.0.3? No problem - fork it, diagnose the issue and push your fixes back up to github.
But that's also a great recipe for yak shaving ;-)
The fixes are yet to make it into the released gem, but if you desparately need 3.0.3 support you can install from my repo. i.e. in your Gemfile:
Blogarhythm: Paranoid (of course - but this is the bluegrass version!)
- packaged as a gem, not a plugin
- built for Rails 3 (arel-aware in particular)
- can be selectively applied to your models
All was cool, except at about the same time we updated to Rails 3.0.3 and it broke (as it turned out, due to changes in AREL 2.0.6 internals).
One of the beautiful things about github and the way it's been adopted by the ruby/rails community in particular is that it makes it so damn easy to just dive in and help update code originally contributed by other people. So paranoid needs updating for Rails 3.0.3? No problem - fork it, diagnose the issue and push your fixes back up to github.
But that's also a great recipe for yak shaving ;-)
The fixes are yet to make it into the released gem, but if you desparately need 3.0.3 support you can install from my repo. i.e. in your Gemfile:
gem 'paranoid', '~> 0.0.10', :require => 'paranoid', :git => 'git://github.com/tardate/paranoid'
Blogarhythm: Paranoid (of course - but this is the bluegrass version!)
Tuesday, December 14, 2010
CruiseControlling Ruby 1.9.2 and Rails 3.0.2
CruiseControl for Ruby from ThoughWorks has long been one of the easiest ways to your rails project under continuous integration.
But there's still an issue that it can't run under Ruby 1.9.x. That's not very good if you are targeting 1.9.2 for your project.
Here's a quick recipe for how you can build a 1.9.2 project with CC, using the wonders of rvm..
In ~/.cruise/projects/my_project_name, edit cruise_config.rb to run a shell script instead of the standard build task (I'm calling it ccbuild.sh and it will be in the root of my git repo):
Add ccbuild.sh to your repository (don't forget to chmod u+x it). It needs to ensure rvm script is loaded and activate the correct ruby & gemset.
The script initialization is necessary because it seems the way CC spawns the shell script it doesn't pick up the rvm initialization you might already have in .bash_profile. Without rvm script initialization, "rvm" will invoke the binary which can't make the direct environment mods it needs to do.
Here's what I have in ccbuild.sh:
Once that's checked in and pushed to the repo, you can kick-off CC:
Now my ccmenu is green, and CruiseControl is running my project under 1.9.2 and rails 3.0.2;-)
Blogarhythm: Waiting for the light ART-SCHOOL
But there's still an issue that it can't run under Ruby 1.9.x. That's not very good if you are targeting 1.9.2 for your project.
Here's a quick recipe for how you can build a 1.9.2 project with CC, using the wonders of rvm..
# download and unpack CC to /usr/local/cruisecontrol-1.4.0 (or where you like)
# for convenience, add .rvmrc in /usr/local/cruisecontrol-1.4.0 to have it run 1.8.7
echo "rvm 1.8.7-p302"> /usr/local/cruisecontrol-1.4.0/.rvmrc
# configure CC:
cd /usr/local/cruisecontrol-1.4.0
./cruise add my_project_name --source-control git --repository git@github.com:myname/myproject.git
# ^^ This will initialize the ~/.cruise/projects/my_project_name folder for a git-based project
# if you have an .rvmrc file in your git repo, pre-emptively trust it to avoid clogging CC:
mkdir ~/.cruise/projects/my_project_name
rvm rvmrc trust ~/.cruise/projects/my_project_name
In ~/.cruise/projects/my_project_name, edit cruise_config.rb to run a shell script instead of the standard build task (I'm calling it ccbuild.sh and it will be in the root of my git repo):
Project.configure do |project|
# [.. other stuff ..]
project.build_command = './ccbuild.sh'
# [.. other stuff ..]
end
Add ccbuild.sh to your repository (don't forget to chmod u+x it). It needs to ensure rvm script is loaded and activate the correct ruby & gemset.
The script initialization is necessary because it seems the way CC spawns the shell script it doesn't pick up the rvm initialization you might already have in .bash_profile. Without rvm script initialization, "rvm" will invoke the binary which can't make the direct environment mods it needs to do.
Here's what I have in ccbuild.sh:
#!/bin/bash
if [ "$(type rvm | head -1)" != "rvm is a function" ]
then
source ~/.rvm/scripts/rvm || exit 1
fi
if [ "$(type rvm | head -1)" != "rvm is a function" ]
then
echo "rvm not properly installed and available"
exit 1
fi
rvm use 1.9.2-p0@mygemsetname --create
bundle check || bundle install || exit 1
rake # setup to run all required tests by default
Once that's checked in and pushed to the repo, you can kick-off CC:
cd /usr/local/cruisecontrol-1.4.0
./cruise start
Now my ccmenu is green, and CruiseControl is running my project under 1.9.2 and rails 3.0.2;-)
Blogarhythm: Waiting for the light ART-SCHOOL
Wednesday, January 20, 2010
Released: Authlogic_RPX 1.1.1 gem now with identity mapping for Rails
Authlogic_RPX is the gem I released some time back that lets you easily support multiple authentication schemes in Rails without really having to think about it (Facebook, twitter, OpenID, Google, Yahoo! etc etc etc).
With thanks for contributions from John and Damir, Authlogic_RPX 1.1.1 is now available and includes an internal identity mapping that lets you tie multiple authentication methods to a single user. There are also some other bug fixes and improvements, so it is recommended you update Authlogic_RPX even if you don't want to enable the identity mapping.
See the Authlogic_RPX repo on github for information about installation, usage, and don't forget the sample site (and sample code).
Under the covers, it uses the RPX service from JanRain, a bit like this:
To get a better idea of why you might want to use Authlogic_RPX, and some pointers on how to do it, here's a reprise of my presentation on the subject to the singapore Ruby Brigade last year:
Soundtrack for this post? (I want) Security Jo Jo Zep & The Falcons. 1977, tight pants, mo and all;-)
With thanks for contributions from John and Damir, Authlogic_RPX 1.1.1 is now available and includes an internal identity mapping that lets you tie multiple authentication methods to a single user. There are also some other bug fixes and improvements, so it is recommended you update Authlogic_RPX even if you don't want to enable the identity mapping.
See the Authlogic_RPX repo on github for information about installation, usage, and don't forget the sample site (and sample code).
Under the covers, it uses the RPX service from JanRain, a bit like this:
To get a better idea of why you might want to use Authlogic_RPX, and some pointers on how to do it, here's a reprise of my presentation on the subject to the singapore Ruby Brigade last year:
Rails authentication with Authlogic RPX[埋込みオブジェクト:http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=srbauthlogicrpx-12549789382598-phpapp01&stripped_title=srbauthlogicrpx]
View more presentations from Paul Gallagher.
Soundtrack for this post? (I want) Security Jo Jo Zep & The Falcons. 1977, tight pants, mo and all;-)
Saturday, January 16, 2010
ActiveWarehouse/ETL and Reflections on BI for Rails
I've recently been considering the opportunity to apply Ruby and Rails goodness to mainstream Business Intelligence applications.
During my research into prior art I discovered Anthony Eden's ActiveWarehouse and ActiveWarehouse-ETL projects, and gave them a test drive using a fictitious "Cupcakes Inc" site.
I presented this at the Jan 2010 Singapore Ruby Brigade meetup held at hackerspace.sg. My "point-of-view" slides are embedded below, and you can find the sample project and doco on github.
Conclusions?
Nevertheless, ActiveWarehouse and ActiveWarehouse-ETL are interesting projects, and the underlying implementations make for some educational code reading. Hopefully my slides and the Cupcakes sample project will add a bit to the available documentation, and give a bit of a leg up to anyone intersted in checking out these projects;-)
[フレーム]Soundtrack for this post: Information Overload- Living Color
During my research into prior art I discovered Anthony Eden's ActiveWarehouse and ActiveWarehouse-ETL projects, and gave them a test drive using a fictitious "Cupcakes Inc" site.
I presented this at the Jan 2010 Singapore Ruby Brigade meetup held at hackerspace.sg. My "point-of-view" slides are embedded below, and you can find the sample project and doco on github.
Conclusions?
- ActiveWarehouse is a textbook implementation of classic data warehousing techniques. That was clearly Anthony's intention, but it also means it does not really attempt to explore how data warehousing might be approached quite differently with Ruby and Rails
- ActiveWarehouse/ETL are not for the faint-hearted. When you get them working, they works well, but the lack of documentation basically means it's inevitable you'll end up reading the sources to figure it all out
- I have concerns about scalability. Having worked on terabyte warehouses using "classic" technology, I know just how far you push databases in order to scale. This bears more investigation and testing before it would be sensible to commit to ActiveWarehouse for a large-scale DWH implementation
Nevertheless, ActiveWarehouse and ActiveWarehouse-ETL are interesting projects, and the underlying implementations make for some educational code reading. Hopefully my slides and the Cupcakes sample project will add a bit to the available documentation, and give a bit of a leg up to anyone intersted in checking out these projects;-)
ActiveWarehouse/ETL - BI & DW for Ruby/Rails[埋込みオブジェクト:http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=srbactivewarehouse-100116080609-phpapp02&stripped_title=activewarehouseetl-bi-dw-for-rubyrails]
View more presentations from Paul Gallagher.
[フレーム]Soundtrack for this post: Information Overload- Living Color
Wednesday, December 30, 2009
Two Ruby Books To Own..
[フレーム]
Design Patterns in Ruby by Russ Olsen is the first technical book in a very long time that I have enjoyed reading from cover to cover.
It's more than just a naïve translation of the classic GoF patterns. Olsen manages the dual trick of not only demonstrating how the classic patterns can still be relevant in Ruby, but how to approach them with the full power of ruby at your disposal.
I liked the way that Olsen avoided doing bare minimum implementations. So when looking at the Composite pattern, he spruces things up with a little operator overloading. And where ruby affords a number of possible approaches, these get discussed and compared (like with the Decorator pattern).
The final chapters in the book present a few additional patterns that go beyond the GoF and are particularly topical and relevant for ruby: DSLs, meta-programming, and convention over configuration.
In short, Design Patterns in Ruby is a grand tour, an effective tutorial in a selection of ruby practices, and ultimately a very enjoyable, rewarding, and sometimes even funny book to read.
[フレーム]The second book I'd stowaway with is Ruby Best Practices by Gregory Brown.
It doesn't pretend to be encyclopedic in the manner of The Ruby Way. However, where sometimes I find The Ruby Way curtails topics just when they start to get interesting, Brown dives deep with Ruby Best Practices.
Clear examples are accompanied by thoughtful and full treatments of the subject at hand. It has particularly useful focus on "Mastering the Dynamic Toolkit", "Text Processing", "Functional Programming Techniques", and "Designing Beautiful APIs".
So they're my picks. Now, obviously these are not ideal books for learning ruby from scratch, but once you're past the basics these are the two at the top of my pile;-)
Anyone willing to counter with their top two picks? Agree or disagree with my choice?
Soundtrack for this post: I Like Your Old Stuff Better than Your New Stuff - Regurgitator from the album Unit Re-Booted
If I had to pick two..
Design Patterns in Ruby by Russ Olsen is the first technical book in a very long time that I have enjoyed reading from cover to cover.
It's more than just a naïve translation of the classic GoF patterns. Olsen manages the dual trick of not only demonstrating how the classic patterns can still be relevant in Ruby, but how to approach them with the full power of ruby at your disposal.
I liked the way that Olsen avoided doing bare minimum implementations. So when looking at the Composite pattern, he spruces things up with a little operator overloading. And where ruby affords a number of possible approaches, these get discussed and compared (like with the Decorator pattern).
The final chapters in the book present a few additional patterns that go beyond the GoF and are particularly topical and relevant for ruby: DSLs, meta-programming, and convention over configuration.
In short, Design Patterns in Ruby is a grand tour, an effective tutorial in a selection of ruby practices, and ultimately a very enjoyable, rewarding, and sometimes even funny book to read.
[フレーム]The second book I'd stowaway with is Ruby Best Practices by Gregory Brown.
It doesn't pretend to be encyclopedic in the manner of The Ruby Way. However, where sometimes I find The Ruby Way curtails topics just when they start to get interesting, Brown dives deep with Ruby Best Practices.
Clear examples are accompanied by thoughtful and full treatments of the subject at hand. It has particularly useful focus on "Mastering the Dynamic Toolkit", "Text Processing", "Functional Programming Techniques", and "Designing Beautiful APIs".
So they're my picks. Now, obviously these are not ideal books for learning ruby from scratch, but once you're past the basics these are the two at the top of my pile;-)
Anyone willing to counter with their top two picks? Agree or disagree with my choice?
Soundtrack for this post: I Like Your Old Stuff Better than Your New Stuff - Regurgitator from the album Unit Re-Booted
Tuesday, December 29, 2009
Understanding Authlogic Plugin Dynamics
authlogic is by far and away my favourite authentication framework for Rails. I've raved enough in my slides on Authlogic_RPX.
It's true beauty is making authentication so unobtrusive for application developers.
However, the same can't be said for Authlogic plugin developers. I spent quite a bit of time meandering through the authlogic source and other plugins in order to produce Authlogic_RPX (the RPX plugin for authlogic, to support JanRain's RPX service).
I recently returned to the Authlogic_RPX in order to provide an update that finally adds identity mapping (with contributions from John and Damir; thanks guys!).
Luckily my previous exploits were recent enough that much of what I learned about authlogic were still pretty fresh. But before I forget it all again, I thought it would be worthwhile to write up a few of the "insights" I had on the authlogic source.
Hence this post. I'm just going to focus on one thing for now. Since authlogic is so "unobtrusive", one of the big conceptual hurdles you need to get over if you are attempting to write an authlogic plugin is simply:
(To follow this discussion, I'd recommend you have a plugin close to hand. Either my previously mentioned Authlogic_RPX, or another like Authlogic_OAuth, or Authlogic_openid)
By unobtrusive, I mean like this. Here is the minimal configuration for a user model that uses Authlogic_RPX:
Pretty simple, right? But what power lies behind that little "acts_as_authentic" statement?
What follows is my attempt at a description of what goes on behind the scenes..
The main file in an authlogic plugin/gem is going to have the relevant requires to the library files. But they do squat. We start mixing in our plugin with the includes and helper registrations:
Note that your plugin ActsAsAuthentic module get's mixed in with ActiveRecord itself (not just a specific ActiveRecord model). That's crucial to remember when considering class methods in your plugin (they are basically global across all ActiveRecord).
What happens when the previous lines included the plugin's ActsAsAuthentic module?
The self.included method handles the initial bootstrap..
Here we see we do a class_eval on the class that the module is included in (i.e. ActiveRecord::Base). You'll immediately get the sense we're doing some kind of mixin with the Config and Methods modules. The Config / Methods module structure is a common pattern you will see throughout authlogic.
extend Config takes the Config module (AuthlogicRpx::ActsAsAuthentic::Config) and add it to the ActiveRecord::Base class cdefinition. i.e. methods defined in Config become class methods of ActiveRecord::Base. (If you add a def self.extended(klass) method to Config you'll be able to hook the extension).
add_acts_as_authentic_module(Methods, :prepend) adds the Methods module (AuthlogicRpx::ActsAsAuthentic::Methods) to the authlogic modules list. That's all. Take a look at add_acts_as_authentic_module:
It is only when we add the acts_as_authentic in our model class that things start to happen. This method loads all the modules from the list built up by all the call(s) to "add_acts_as_authentic_module". Note the include in the last line of the method:
Once the include is invoked, our plugin will usually hook the event and do some setup activity in our module's def self.included method.
Unlike the Config extension, the class you are including in (the klass parameter in the example), is the specific ActiveRecord model you have marked as "acts_as_authentic".
In other words, the methods in the Methods module get included as instance methods for the specific ActiveRecord models class (User in the example I presented earlier).
Let's hang it all out in a simplified and contrived example. Take this basic structure:
If we add this to our User model, then the result we'd end up with is this:
I've covered the main points in bootstrapping authlogic. There's obviously a lot more that goes on, but I think once you get these basics it makes authlogic-related code so much easier to read and understand. It's a pretty neat demonstration of dynamic ruby at work.
Understanding the loading process is also makes it possible to be definitive about how your application will behave, rather than just treating it as a heuristic black box.
Take authlogic configuration settings for example. Say we have a configuration parameter in our plugin called "big_red_button" that takes values :on and :off.
Syntactically, both of these user model definitions are valid:
However, the behaviour is slightly different, and the difference will be significant if you have any initialisation code in the plugin that cares about the setting of the big_red_button.
In the second case, it should be clear that setting big_red_button :on only happens after all the plugin initialisation is complete.
But in the first case, it is a little more subtle. If you go back to review the acts_as_authentic method you'll see that setting the big_red_button occurs at yield self if block_given?. Implications:
How's that? Pretty cool stuff, but thankfully as I mentioned before, these details only really concern plugin authors and anyone who just loves to read dynamic ruby code.
There's much more to authlogic that what I've discussed here of course (and RPX). Perhaps good fodder for a future post? Let's see..
Soundtrack for this post: Because it's There - Michael Hedges
It's true beauty is making authentication so unobtrusive for application developers.
However, the same can't be said for Authlogic plugin developers. I spent quite a bit of time meandering through the authlogic source and other plugins in order to produce Authlogic_RPX (the RPX plugin for authlogic, to support JanRain's RPX service).
I recently returned to the Authlogic_RPX in order to provide an update that finally adds identity mapping (with contributions from John and Damir; thanks guys!).
Luckily my previous exploits were recent enough that much of what I learned about authlogic were still pretty fresh. But before I forget it all again, I thought it would be worthwhile to write up a few of the "insights" I had on the authlogic source.
Hence this post. I'm just going to focus on one thing for now. Since authlogic is so "unobtrusive", one of the big conceptual hurdles you need to get over if you are attempting to write an authlogic plugin is simply:
Just how the heck does it all get loaded and mixed in with my models??
(To follow this discussion, I'd recommend you have a plugin close to hand. Either my previously mentioned Authlogic_RPX, or another like Authlogic_OAuth, or Authlogic_openid)
By unobtrusive, I mean like this. Here is the minimal configuration for a user model that uses Authlogic_RPX:
class User < ActiveRecord::Base
acts_as_authentic
end
Pretty simple, right? But what power lies behind that little "acts_as_authentic" statement?
What follows is my attempt at a description of what goes on behind the scenes..
First: get loaded
The main file in an authlogic plugin/gem is going to have the relevant requires to the library files. But they do squat. We start mixing in our plugin with the includes and helper registrations:
require "authlogic_rpx/version"
require "authlogic_rpx/acts_as_authentic"
require "authlogic_rpx/session"
require "authlogic_rpx/helper"
require "authlogic_rpx/rpx_identifier"
ActiveRecord::Base.send(:include, AuthlogicRpx::ActsAsAuthentic)
Authlogic::Session::Base.send(:include, AuthlogicRpx::Session)
ActionController::Base.helper AuthlogicRpx::Helper
Note that your plugin ActsAsAuthentic module get's mixed in with ActiveRecord itself (not just a specific ActiveRecord model). That's crucial to remember when considering class methods in your plugin (they are basically global across all ActiveRecord).
What including ActsAsAuthentic in ActiveRecord::Base does..
What happens when the previous lines included the plugin's ActsAsAuthentic module?
The self.included method handles the initial bootstrap..
module AuthlogicRpx
module ActsAsAuthentic
def self.included(klass)
klass.class_eval do
extend Config
add_acts_as_authentic_module(Methods, :prepend)
end
end
..
Here we see we do a class_eval on the class that the module is included in (i.e. ActiveRecord::Base). You'll immediately get the sense we're doing some kind of mixin with the Config and Methods modules. The Config / Methods module structure is a common pattern you will see throughout authlogic.
extend Config takes the Config module (AuthlogicRpx::ActsAsAuthentic::Config) and add it to the ActiveRecord::Base class cdefinition. i.e. methods defined in Config become class methods of ActiveRecord::Base. (If you add a def self.extended(klass) method to Config you'll be able to hook the extension).
add_acts_as_authentic_module(Methods, :prepend) adds the Methods module (AuthlogicRpx::ActsAsAuthentic::Methods) to the authlogic modules list. That's all. Take a look at add_acts_as_authentic_module:
def add_acts_as_authentic_module(mod, action = :append)
modules = acts_as_authentic_modules
case action
when :append
modules << mod
when :prepend
modules = [mod] + modules
end
modules.uniq!
write_inheritable_attribute(:acts_as_authentic_modules, modules)
end
Ready to launch..
It is only when we add the acts_as_authentic in our model class that things start to happen. This method loads all the modules from the list built up by all the call(s) to "add_acts_as_authentic_module". Note the include in the last line of the method:
def acts_as_authentic(unsupported_options = nil, &block)
# Stop all configuration if the DB is not set up
return if !db_setup?
raise ArgumentError.new("You are using the old v1.X.X configuration method for Authlogic. Instead of " +
"passing a hash of configuration options to acts_as_authentic, pass a block: acts_as_authentic { |c| c.my_option = my_value }") if !unsupported_options.nil?
yield self if block_given?
acts_as_authentic_modules.each { |mod| include mod }
end
Ignition..
Once the include is invoked, our plugin will usually hook the event and do some setup activity in our module's def self.included method.
module Methods
def self.included(klass)
klass.class_eval do
..
end
..
end
..
Unlike the Config extension, the class you are including in (the klass parameter in the example), is the specific ActiveRecord model you have marked as "acts_as_authentic".
In other words, the methods in the Methods module get included as instance methods for the specific ActiveRecord models class (User in the example I presented earlier).
Hanging it on the line..
Let's hang it all out in a simplified and contrived example. Take this basic structure:
module AuthlogicPlugin
module ActsAsAuthentic
def self.included(klass)
klass.class_eval do
extend Config
add_acts_as_authentic_module(Methods, :prepend)
end
end
module Config
def config_item
end
end
module Methods
def self.included(klass)
klass.class_eval do
def self.special_setting
end
end
end
def instance_item
end
end
end
end
If we add this to our User model, then the result we'd end up with is this:
- config_item: will be a class method on ActiveRecord::Base
- instance_item: will be an instance method on User
- special_setting: will be a class method on User
Conclusions & Implications?
I've covered the main points in bootstrapping authlogic. There's obviously a lot more that goes on, but I think once you get these basics it makes authlogic-related code so much easier to read and understand. It's a pretty neat demonstration of dynamic ruby at work.
Understanding the loading process is also makes it possible to be definitive about how your application will behave, rather than just treating it as a heuristic black box.
Take authlogic configuration settings for example. Say we have a configuration parameter in our plugin called "big_red_button" that takes values :on and :off.
Syntactically, both of these user model definitions are valid:
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.big_red_button :on
end
end
class User < ActiveRecord::Base
acts_as_authentic
big_red_button :on
end
However, the behaviour is slightly different, and the difference will be significant if you have any initialisation code in the plugin that cares about the setting of the big_red_button.
In the second case, it should be clear that setting big_red_button :on only happens after all the plugin initialisation is complete.
But in the first case, it is a little more subtle. If you go back to review the acts_as_authentic method you'll see that setting the big_red_button occurs at yield self if block_given?. Implications:
- Config extension of ActiveRecord::Base takes place before the big_red_button is set
- Method methods are included in the User model before the big_red_button is set
- Method's def self.included is called after the big_red_button is set (meaning you can safely do conditional initialisation here based on the big_red_button setting)
How's that? Pretty cool stuff, but thankfully as I mentioned before, these details only really concern plugin authors and anyone who just loves to read dynamic ruby code.
There's much more to authlogic that what I've discussed here of course (and RPX). Perhaps good fodder for a future post? Let's see..
Soundtrack for this post: Because it's There - Michael Hedges
Thursday, October 08, 2009
Rails authentication with Authlogic and RPX
The Singapore Ruby Brigade had it's monthly meetup last night. Great discussions as always, and how can you complain when you get to carry on over maggi mee goreng supper until the wee hours;-)
Here are the slides from my talk about Rails authentication options in general, and specifically why and how to use RPX with Authlogic (using the Authlogic_RPX gem I released last week).
Sunday, September 27, 2009
Released: Authlogic_RPX gem, the easiest way to support multiple authentication schemes in Rails
I've just made Authlogic_RPX public for the first time and invite any rails developers to take a look. It's a ruby gem that adds suppport for RPX authentication in the Authlogic framework for Ruby on Rails. With RPX, you get to support all the common authentication schemes in one shot (Facebook, twitter, OpenID etc).
Authlogic_RPX is available under the MIT license, and a number of resources are available:
The best place to find out more is the README, it contains the full background and details on how to start using it. Feedback and comments are welcome and invited (either directly to me, or you can enter them in the github issues list for the project).
Authlogic_RPX plugs into the fantastic Authlogic framework by Ben Johnson/binarylogic. Authlogic is elegant and unobtrusive, making it currently one of the more popular approaches to authentication in Rails.
RPX is the website single-sign-on service provided by JanRain (the OpenID folks). It complements their OPX offerings I wrote about recently. RPX abstracts the authentication process for developers and provides a single, simple API to deal with. This approach is great for developers because you only need to build a single authentication integration, and leave to JanRain the messy details of implementing and maintaining support for the range of authentication providers: OpenID, OAuth, Facebook Connect, AOL, Yahoo, Google, and so on..
If you want to learn more, there was recently a great podcast interview with Brian Ellin from JanRain on the IT Conversations Network: RPX and Identity Systems
Authlogic_RPX is available under the MIT license, and a number of resources are available:
- Authlogic_RPX source repository: github.com/tardate/authlogic_rpx
- Live Demonstration Site: rails-authlogic-rpx-sample.heroku.com
- Demonstration site source repository: github.com/tardate/rails-authlogic-rpx-sample
The best place to find out more is the README, it contains the full background and details on how to start using it. Feedback and comments are welcome and invited (either directly to me, or you can enter them in the github issues list for the project).
Authlogic_RPX plugs into the fantastic Authlogic framework by Ben Johnson/binarylogic. Authlogic is elegant and unobtrusive, making it currently one of the more popular approaches to authentication in Rails.
RPX is the website single-sign-on service provided by JanRain (the OpenID folks). It complements their OPX offerings I wrote about recently. RPX abstracts the authentication process for developers and provides a single, simple API to deal with. This approach is great for developers because you only need to build a single authentication integration, and leave to JanRain the messy details of implementing and maintaining support for the range of authentication providers: OpenID, OAuth, Facebook Connect, AOL, Yahoo, Google, and so on..
If you want to learn more, there was recently a great podcast interview with Brian Ellin from JanRain on the IT Conversations Network: RPX and Identity Systems
Tuesday, October 21, 2008
Rolling Project Euler on Ruby
I first heard about Project Euler last week on the stackoverflow podcast. Michael Pryor (fogcreek co-founder) makes a quick side reference in discussion with Joel Spolsky, Jeff Atwood and the rest of the SO team.
Well I checked it out last week, got hooked and spent most of the weekend earning my "level 1" badge;-)
Aside from dusting off some long-forgotten and arcane knowledge from my youth, I found it a fantastic opportunity to stretch my fundamental ruby chops. In fact, I'd recommend a few questions at Project Euler as a right-of-passage whenever you are learning a new programming language.
I've only been using ruby for a year or so, and in that time thought I had picked up a fair bit. But I was still able to amaze myself at just how many of the problems were knocked over in just 1 or 2 lines with a bit of duck punching and liberal use of blocks with Enumerables.
I'm late to the Project Euler craze, so you will already find many people posting hints for specific questions if you just google. I thought I'd share some of the "common code" I've been building up as I go through the questions.
I put a recent copy of the source up on github for anyone who is interested (MyMath.rb), but what follows a sampling of some of the more interesting pieces.
First thing you will note is that I have written all these "common" routines as extensions to some of the fundamental classes in the ruby library: Integer, Array, String.
It doesn't have to be this way, and for less trivial activities you might be right to be concerned about messing with the behaviour of the standard classes. Maybe I'm still enjoying my ruby honeymoon period, but I do get a thrill out of being able to write things like
It's just so easy to code up simple calculation and introspection routines..
Prime numbers feature heavily on Project Euler, and I think calculating a prime series was my first lesson on why you can't brute-force everything;-) Enter the Sieve of Eratosthenes and related goodness..
Next we visit the Collatz conjecture and an interesting routine to make numbers "speak english"..
Calculating integer partitions is one of my favourites ... a nice, super-fast recursive algorithm. For problems like "how many ways to make 2ドル in change?"
Finally, rotations and palindromes (base 2 or 10): methods that rely on some underlying String routines that come later...
Array handling is particularly important. Start with some simple helpers, then move onto greatest common factor and a couple of least-common multiple implementations. My favourite here - lexicographic permutations.
Last but not least, some String methods that just make things so much easier...
With all the above in place - and with the aid of a few brain cells - some deceptively complicated questions (like "How many different ways can £2 be made using any number of coins?") are essentially one-liners:
Love it;-)
Well I checked it out last week, got hooked and spent most of the weekend earning my "level 1" badge;-)
Aside from dusting off some long-forgotten and arcane knowledge from my youth, I found it a fantastic opportunity to stretch my fundamental ruby chops. In fact, I'd recommend a few questions at Project Euler as a right-of-passage whenever you are learning a new programming language.
I've only been using ruby for a year or so, and in that time thought I had picked up a fair bit. But I was still able to amaze myself at just how many of the problems were knocked over in just 1 or 2 lines with a bit of duck punching and liberal use of blocks with Enumerables.
I'm late to the Project Euler craze, so you will already find many people posting hints for specific questions if you just google. I thought I'd share some of the "common code" I've been building up as I go through the questions.
I put a recent copy of the source up on github for anyone who is interested (MyMath.rb), but what follows a sampling of some of the more interesting pieces.
First thing you will note is that I have written all these "common" routines as extensions to some of the fundamental classes in the ruby library: Integer, Array, String.
It doesn't have to be this way, and for less trivial activities you might be right to be concerned about messing with the behaviour of the standard classes. Maybe I'm still enjoying my ruby honeymoon period, but I do get a thrill out of being able to write things like
1551.palindrome?
=> true
Integer Extensions
It's just so easy to code up simple calculation and introspection routines..
class Integer
# @see project euler #15,20,34
def factorial
(2..self).inject(1) { |prod, n| prod * n }
end
# sum of digits in the number, expressed as a decimal
# @see project euler #16, 20
def sum_digits
self.to_s.split('').inject(0) { |memo, c| memo + c.to_i }
end
# num of digits in the number, expressed as a decimal
# @see project euler #25
def num_digits
self.to_s.length
end
# tests if all the base10 digits in the number are odd
# @see project euler #35
def all_digits_odd?
self.to_s.split('').inject(0) { |memo, s| memo + ( s.to_i%2==0 ? 1 : 0 ) } == 0
end
# generates triangle number for this integer
# http://en.wikipedia.org/wiki/Triangle_number
# @see project euler #42
def triangle
self * ( self + 1 ) / 2
end
end
Prime numbers feature heavily on Project Euler, and I think calculating a prime series was my first lesson on why you can't brute-force everything;-) Enter the Sieve of Eratosthenes and related goodness..
class Integer
# http://en.wikipedia.org/wiki/Prime_factor
# @see project euler #12
def prime_factors
primes = Array.new
d = 2
n = self
while n > 1
if n%d==0
primes << d
n/=d
else
d+=1
end
end
primes
end
# http://en.wikipedia.org/wiki/Divisor_function
# @see project euler #12
def divisor_count
primes = self.prime_factors
primes.uniq.inject(1) { |memo, p| memo * ( ( primes.find_all {|i| i == p} ).length + 1) }
end
#
# @see project euler #12, 21, 23
def divisors
d = Array.new
(1..self-1).each { |n| d << n if self % n == 0 }
d
end
# @see project euler #
def prime?
divisors.length == 1 # this is a brute force check
end
# prime series up to this limit, using Sieve of Eratosthenes method
# http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
# @see project euler #7, 10, 35
def prime_series
t = self
limit = Math.sqrt(t)
a = (2..t).to_a
n = 2
while (n < limit) do
x = n*2
begin
a[x-2]=2
x+=n
end until (x > t )
begin
n+=1
end until ( a[n-2] != 2 )
end
a.uniq!
end
# @see project euler #23
def perfect?
self == divisors.sum
end
# @see project euler #23
def deficient?
self > divisors.sum
end
# @see project euler #23
def abundant?
self < divisors.sum
end
end
Next we visit the Collatz conjecture and an interesting routine to make numbers "speak english"..
class Integer
# http://en.wikipedia.org/wiki/Collatz_conjecture
# @see project euler #14
def collatz_series
a = Array.new
a << n = self
while n > 1
if n % 2 == 0
n /= 2
else
n = 3*n + 1
end
a << n
end
a
end
# express integer as an english phrase
# @see project euler #17
def speak
case
when self <20
["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" ][self]
when self > 19 && self < 100
a = ["twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"][self / 10 - 2]
r = self % 10
if r == 0
a
else
a + "-" + r.speak
end
when self > 99 && self < 1000
a = (self / 100).speak + " hundred"
r = self % 100
if r == 0
a
else
a + " and " + r.speak
end
when self > 999 && self < 10000
a = (self / 1000).speak + " thousand"
r = self % 1000
if r == 0
a
else
a + ( r <100 ? " and " : " " ) + r.speak
end
else
self
end
end
end
Calculating integer partitions is one of my favourites ... a nice, super-fast recursive algorithm. For problems like "how many ways to make 2ドル in change?"
class Integer
# calculates integer partitions for given number using array of elements
# http://en.wikipedia.org/wiki/Integer_partition
# @see project euler #31
def integer_partitions(pArray, p=0)
if p==pArray.length-1
1
else
self >= 0 ? (self - pArray[p]).integer_partitions(pArray ,p) + self.integer_partitions(pArray,p+1) : 0
end
end
end
Finally, rotations and palindromes (base 2 or 10): methods that rely on some underlying String routines that come later...
class Integer
# returns an array of all the base10 digit rotations of the number
# @see project euler #35
def rotations
self.to_s.rotations.collect { |s| s.to_i }
end
# @see project euler #4, 36, 91
def palindrome?(base = 10)
case base
when 2
sprintf("%0b",self).palindrome?
else
self.to_s.palindrome?
end
end
end
Array Manipulations
Array handling is particularly important. Start with some simple helpers, then move onto greatest common factor and a couple of least-common multiple implementations. My favourite here - lexicographic permutations.
class Array
# sum elements in the array
def sum
self.inject(0) { |sum, n| sum + n }
end
# sum of squares for elements in the array
# @see project euler #6
def sum_of_squares
self.inject(0) { |sos, n| sos + n**2 }
end
# @see project euler #17
def square_of_sum
( self.inject(0) { |sum, n| sum + n } ) ** 2
end
# index of the smallest item in the array
def index_of_smallest
value, index = self.first, 0
self.each_with_index {| obj, i | value, index = obj, i if obj<value }
index
end
# removes numbers from the array that are factors of other elements in the array
# @see project euler #5
def remove_factors
a=Array.new
self.each do | x |
a << x if 0 == ( self.inject(0) { | memo, y | memo + (x!=y && y%x==0 ? 1 : 0) } )
end
a
end
# http://utilitymill.com/edit/GCF_and_LCM_Calculator
# @see project euler #5
def GCF
t_val = self[0]
for cnt in 0...self.length-1
num1 = t_val
num2 = self[cnt+1]
num1,num2=num2,num1 if num1 < num2
while num1 - num2 > 0
num3 = num1 - num2
num1 = [num2,num3].max
num2 = [num2,num3].min
end
t_val = num1
end
t_val
end
# http://utilitymill.com/edit/GCF_and_LCM_Calculator
# @see project euler #5
def LCM
a=self.remove_factors
t_val = a[0]
for cnt in 0...a.length-1
num1 = t_val
num2 = a[cnt+1]
tmp = [num1,num2].GCF
t_val = tmp * num1/tmp * num2/tmp
end
t_val
end
# brute force method:
# http://www.cut-the-knot.org/Curriculum/Arithmetic/LCM.shtml
# @see project euler #5
def lcm2
a=self.remove_factors
c=a.dup
while c.uniq.length>1
index = c.index_of_smallest
c[index]+=a[index]
end
c.first
end
# returns the kth Lexicographical permutation of the elements in the array
# http://en.wikipedia.org/wiki/Permutation#Lexicographical_order_generation
# @see project euler #24
def lexicographic_permutation(k)
k -= 1
s = self.dup
n = s.length
n_less_1_factorial = (n - 1).factorial # compute (n - 1)!
(1..n-1).each do |j|
tempj = (k / n_less_1_factorial) % (n + 1 - j)
s[j-1..j+tempj-1]=s[j+tempj-1,1]+s[j-1..j+tempj-2] unless tempj==0
n_less_1_factorial = n_less_1_factorial / (n- j)
end
s
end
# returns ordered array of all the lexicographic permutations of the elements in the array
# http://en.wikipedia.org/wiki/Permutation#Lexicographical_order_generation
# @see project euler #24
def lexicographic_permutations
a=Array.new
(1..self.length.factorial).each { |i| a << self.lexicographic_permutation(i) }
a
end
end
String Helpers
Last but not least, some String methods that just make things so much easier...
class String
# sum of digits in the number
# @see project euler #16, 20
def sum_digits
self.split('').inject(0) { |memo, c| memo + c.to_i }
end
# product of digits in the number
# @see project euler #8
def product_digits
self.split('').inject(1) { |memo, c| memo * c.to_i }
end
#
# @see project euler #4, 36, 91
def palindrome?
self==self.reverse
end
# returns an array of all the character rotations of the string
# @see project euler #35
def rotations
s = self
rots = Array[s]
(1..s.length-1).each do |i|
s=s[1..s.length-1]+s[0,1]
rots << s
end
rots
end
end
With all the above in place - and with the aid of a few brain cells - some deceptively complicated questions (like "How many different ways can £2 be made using any number of coins?") are essentially one-liners:
require 'benchmark'
require 'MyMath'
Benchmark.bm do |r|
r.report {
answer = 200.integer_partitions([200,100,50,20,10,5,2,1])
}
end
Love it;-)
Subscribe to:
Comments (Atom)