diff --git a/episode-303/url_formatter b/episode-303/url_formatter deleted file mode 160000 index 3716c8c8..00000000 --- a/episode-303/url_formatter +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3716c8c8b652cc07e9a22926e8b708e20978ca7d diff --git a/episode-303/url_formatter/.gitignore b/episode-303/url_formatter/.gitignore new file mode 100644 index 00000000..4040c6c1 --- /dev/null +++ b/episode-303/url_formatter/.gitignore @@ -0,0 +1,4 @@ +*.gem +.bundle +Gemfile.lock +pkg/* diff --git a/episode-303/url_formatter/.rspec b/episode-303/url_formatter/.rspec new file mode 100644 index 00000000..4e1e0d2f --- /dev/null +++ b/episode-303/url_formatter/.rspec @@ -0,0 +1 @@ +--color diff --git a/episode-303/url_formatter/.travis.yml b/episode-303/url_formatter/.travis.yml new file mode 100644 index 00000000..74889f3f --- /dev/null +++ b/episode-303/url_formatter/.travis.yml @@ -0,0 +1,2 @@ +rvm: + - 1.9.2 \ No newline at end of file diff --git a/episode-303/url_formatter/CHANGELOG.md b/episode-303/url_formatter/CHANGELOG.md new file mode 100644 index 00000000..f9e5c687 --- /dev/null +++ b/episode-303/url_formatter/CHANGELOG.md @@ -0,0 +1,3 @@ +## v0.0.1 + +* initial release diff --git a/episode-303/url_formatter/Gemfile b/episode-303/url_formatter/Gemfile new file mode 100644 index 00000000..5717c8d9 --- /dev/null +++ b/episode-303/url_formatter/Gemfile @@ -0,0 +1,4 @@ +source "http://rubygems.org" + +# Specify your gem's dependencies in url_formatter.gemspec +gemspec diff --git a/episode-303/url_formatter/LICENSE b/episode-303/url_formatter/LICENSE new file mode 100644 index 00000000..883e9c10 --- /dev/null +++ b/episode-303/url_formatter/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2011 Ryan Bates + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/episode-303/url_formatter/README.md b/episode-303/url_formatter/README.md new file mode 100644 index 00000000..f090b750 --- /dev/null +++ b/episode-303/url_formatter/README.md @@ -0,0 +1,34 @@ +# URL Formatter [![Build Status](https://secure.travis-ci.org/ryanb/url_formatter.png)](http://travis-ci.org/ryanb/url_formatter) + +Format and validate a URL attribute in Active Record. This is an example gem created for [RailsCasts episode #301](http://railscasts.com/episodes/301-extracting-a-ruby-gem). + + +## Installation + +Add to your Gemfile and run the `bundle` command to install it. + +```ruby +gem "url_formatter" +``` + +**Requires Ruby 1.9.2 or later.** + + +## Usage + +Call [format_url](http://rubydoc.info/github/ryanb/url_formatter/master/UrlFormatter/ModelAdditions:format_url) in an ActiveRecord class and pass the name of the attribute you wish to format into a URL and validate. + +```ruby +class Comment < ActiveRecord::Base + format_url :website +end +``` + +This will automatically add "http://" to the beginning of the `website` attribute upon saving if no protocol is present. It will also do validation to ensure it looks like a URL. + + +## Development + +Questions or problems? Please post them on the [issue tracker](https://github.com/ryanb/url_formatter/issues). You can contribute changes by forking the project and submitting a pull request. You can ensure the tests passing by running `bundle` and `rake`. + +This gem is created by Ryan Bates and is under the MIT License. diff --git a/episode-303/url_formatter/Rakefile b/episode-303/url_formatter/Rakefile new file mode 100644 index 00000000..c382feeb --- /dev/null +++ b/episode-303/url_formatter/Rakefile @@ -0,0 +1,6 @@ +require "bundler/gem_tasks" +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) + +task default: :spec diff --git a/episode-303/url_formatter/lib/url_formatter.rb b/episode-303/url_formatter/lib/url_formatter.rb new file mode 100644 index 00000000..5bf7023e --- /dev/null +++ b/episode-303/url_formatter/lib/url_formatter.rb @@ -0,0 +1,17 @@ +require "url_formatter/version" +require "url_formatter/model_additions" +require "url_formatter/railtie" if defined? Rails + +module UrlFormatter + def self.format_url(url) + if url.to_s !~ url_regexp && "http://#{url}" =~ url_regexp + "http://#{url}" + else + url + end + end + + def self.url_regexp + /^https?:\/\/([^\s:@]+:[^\s:@]*@)?[-[[:alnum:]]]+(\.[-[[:alnum:]]]+)+\.?(:\d{1,5})?([\/?]\S*)?$/iux + end +end diff --git a/episode-303/url_formatter/lib/url_formatter/model_additions.rb b/episode-303/url_formatter/lib/url_formatter/model_additions.rb new file mode 100644 index 00000000..be40b8e9 --- /dev/null +++ b/episode-303/url_formatter/lib/url_formatter/model_additions.rb @@ -0,0 +1,20 @@ +module UrlFormatter + module ModelAdditions + # To format and validate a URL attribute, call format_url + # in any Active Record model class and pass it the name of an attribute. + # + # class User < ActiveRecord::Base + # format_url :website + # end + # + # This will add a before_validation callback to add "http://" to + # the attribute if a protocol doesn't exist already. It then validates the + # format of the URL. + def format_url(attribute) + before_validation do + send("#{attribute}=", UrlFormatter.format_url(send(attribute))) + end + validates_format_of attribute, with: UrlFormatter.url_regexp, message: "is not a valid URL" + end + end +end diff --git a/episode-303/url_formatter/lib/url_formatter/railtie.rb b/episode-303/url_formatter/lib/url_formatter/railtie.rb new file mode 100644 index 00000000..135b01c9 --- /dev/null +++ b/episode-303/url_formatter/lib/url_formatter/railtie.rb @@ -0,0 +1,9 @@ +module UrlFormatter + class Railtie < Rails::Railtie + initializer 'url_formatter.model_additions' do + ActiveSupport.on_load :active_record do + extend ModelAdditions + end + end + end +end \ No newline at end of file diff --git a/episode-303/url_formatter/lib/url_formatter/version.rb b/episode-303/url_formatter/lib/url_formatter/version.rb new file mode 100644 index 00000000..c71a9e35 --- /dev/null +++ b/episode-303/url_formatter/lib/url_formatter/version.rb @@ -0,0 +1,3 @@ +module UrlFormatter + VERSION = "0.0.2.alpha" +end diff --git a/episode-303/url_formatter/spec/spec_helper.rb b/episode-303/url_formatter/spec/spec_helper.rb new file mode 100644 index 00000000..4cdbf57b --- /dev/null +++ b/episode-303/url_formatter/spec/spec_helper.rb @@ -0,0 +1,2 @@ +require 'url_formatter' +require 'supermodel' \ No newline at end of file diff --git a/episode-303/url_formatter/spec/url_formatter/model_additions_spec.rb b/episode-303/url_formatter/spec/url_formatter/model_additions_spec.rb new file mode 100644 index 00000000..672a92ba --- /dev/null +++ b/episode-303/url_formatter/spec/url_formatter/model_additions_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +class Comment < SuperModel::Base + include ActiveModel::Validations::Callbacks + extend UrlFormatter::ModelAdditions + format_url :website +end + +describe UrlFormatter::ModelAdditions do + it "adds http:// to URL upon saving" do + Comment.create!(website: "example.com").website.should eq("http://example.com") + Comment.create!(website: "http://example.com").website.should eq("http://example.com") + end + + it "validates URL format" do + comment = Comment.new(website: "foo bar") + comment.should_not be_valid + comment.errors[:website].should eq(["is not a valid URL"]) + comment.website = "example.com" + comment.should be_valid + end +end diff --git a/episode-303/url_formatter/spec/url_formatter_spec.rb b/episode-303/url_formatter/spec/url_formatter_spec.rb new file mode 100644 index 00000000..496a466a --- /dev/null +++ b/episode-303/url_formatter/spec/url_formatter_spec.rb @@ -0,0 +1,53 @@ +# encoding: utf-8 +require 'spec_helper' + +describe UrlFormatter do + describe ".format_url" do + it "adds http:// to a URL if not provided" do + UrlFormatter.format_url("example.com").should eq("http://example.com") + end + + it "does not add http:// to a URL if already provided" do + UrlFormatter.format_url("http://example.com").should eq("http://example.com") + end + + it "returns an invalid URL unchanged" do + UrlFormatter.format_url("foo bar").should eq("foo bar") + UrlFormatter.format_url(nil).should eq(nil) + end + end + + describe ".url_regexp" do + it "matches valid URLs" do + [ + 'http://example.com/', + 'HTTP://E-XAMLE.COM', + 'https://example.co.uk./foo', + 'http://example.com:8080', + 'http://www.example.com/anything/after?slash', + 'http://www.example.com?anything_after=question', + 'http://user123:sEcr3t@example.com', + 'http://user123:@example.com', + 'http://example.com/~user', + 'http://1.2.3.4:8080', + 'http://ütf8.com', + ].each do |url| + url.should match(UrlFormatter.url_regexp) + end + end + + it "does not match invalid URLs" do + [ + "www.example.com", + "http://", + "http://example..com", + "http://e xample.com", + "http://example.com/foo bar", + "http://example", # technically valid but not what we want from user + "other://example.com", # we also don't want other protocols + ].each do |url| + url.should_not match(UrlFormatter.url_regexp) + end + end + end +end diff --git a/episode-303/url_formatter/url_formatter.gemspec b/episode-303/url_formatter/url_formatter.gemspec new file mode 100644 index 00000000..49b3422b --- /dev/null +++ b/episode-303/url_formatter/url_formatter.gemspec @@ -0,0 +1,24 @@ +# -*- encoding: utf-8 -*- +$:.push File.expand_path("../lib", __FILE__) +require "url_formatter/version" + +Gem::Specification.new do |s| + s.name = "url_formatter" + s.version = UrlFormatter::VERSION + s.authors = ["Ryan Bates"] + s.email = ["ryan@railscasts.com"] + s.homepage = "https://github.com/ryanb/url_formatter" + s.summary = %q{Format and validate a URL in Active Record} + s.description = %q{Example of creating a Ruby Gem for RailsCasts episode #301} + + s.rubyforge_project = "url_formatter" + + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } + s.require_paths = ["lib"] + + s.add_development_dependency "rake" + s.add_development_dependency "rspec" + s.add_development_dependency "supermodel" +end