Permalink
Browse files

all specs pass

  • Loading branch information...
1 parent b913054 commit 5aa937de991b0f4ec9576083f0b5d9ffe5811b44 @kristianmandrup committed Aug 16, 2012
Showing with 177 additions and 58 deletions.
  1. +27 −19 README.md
  2. +40 −33 lib/picturefill/view_helper.rb
  3. +70 −0 spec/picturefill/view_helper_spec.rb
  4. +40 −6 spec/spec_helper.rb
View
@@ -1,6 +1,6 @@
# Picturefill View helpers for Rails
-[picturefill](https://github.com/scottjehl/picturefill) is currently the best "hack" for rendering Responsive Images on a web page.
+[picturefill](https://github.com/scottjehl/picturefill) is currently the best way for rendering [Responsive Images](http://5by5.tv/webahead/25) on a web page.
*picturefill-rails* provides nice view helper methods to render the picturefill.
@@ -22,37 +22,45 @@
</div>
```
-Can now be written like this, using the provided View helpers:
+The above can be rendered in Rails 3+ by writing the following code, using the View helpers provided by the Rails engine included:
```haml
= picturefill 'A giant stone face at The Bayon temple in Angkor Thom, Cambodia' do
- = pic_src 'small.jpg'
- = pic_src 'small.jpg', "(min-device-pixel-ratio: 2.0)"
- = pic_src 'medium.jpg', "(min-width: 400px)"
- = pic_src 'medium_x2.jpg', "(min-width: 400px) and (min-device-pixel-ratio: 2.0)"
+ = picture_src 'small.jpg'
+ = picture_src 'small.jpg', "(min-device-pixel-ratio: 2.0)"
+ = picture_src 'medium.jpg', "(min-width: 400px)"
+ = picture_src 'medium_x2.jpg', "(min-width: 400px) and (min-device-pixel-ratio: 2.0)"
+ = picture_src 'largs.jpg', "(min-width: 800px)"
+ = picture_src 'large_x2.jpg', "(min-width: 800px) and (min-device-pixel-ratio: 2.0)"
```
-## Convenience functionality
+Note: This example uses [HAML](https://github.com/haml/haml) as the rendering engine.
-Obviously there is huge potential to cut down on the bloat here by taking advantage of common conventions. Fx if the image src name ends in fx `_x2` it should auto-concatenate
-`(min-device-pixel-ratio: 2.0)` to the `data-media` attribute.
+### Optimizations using conventions
-If you use a `ratio: 'x2'` option to `#pic_src` it should auto-generate the complete 'x2' version of the image source using this convention.
-
-### Optimized
-
-Using the convenience functionality:
+Using conventions, and an extra `ratio:` option, the following shorthand is possible:
```haml
= picturefill 'A giant stone face at The Bayon temple in Angkor Thom, Cambodia' do
- = pic_src 'small.jpg', ratio: 'x2'
- = pic_src 'medium.jpg', "400", ratio: 'x2'
- = pic_src 'large.jpg', "800", ratio: 'x2'
+ = picture_src 'small.jpg', ratio: 'x2'
+ = picture_src 'medium.jpg', "400", ratio: 'x2'
+ = picture_src 'large.jpg', "800", ratio: 'x2'
```
-Please help contribute this functionality ;)
+This will ouput exactly the same HTML as the previous example :)
+See the specs for more details...
+
+## Usage
+
+In your Gemfile:
+
+`gem 'picturefill-rails'`
+
+A number of specs are included which all pass and should ensure that the view helpers work as expected.
+
+## TODO
-PS: Currently not tested and code needs to be refactored somewhat...
+The `#picture_src` method works, but could use some heavy refactoring! I don't like methods of more than 10 lines! Is a bad sign. Reponsibilities should be off-loaded to other methods (or classes)
## Contributing to picturefill-rails
@@ -1,63 +1,70 @@
module Picturefill
- class ViewHelper
+ module ViewHelper
def picturefill options = {}, &block
- alt = options.delete(:alt]
- clazz = options.delete(:class)
- opts = options.merge(:"data-alt" => alt, :"class" => clazz, :"data-picture" => true)
+ opts = {}
+ alt = options.delete :alt
+ clazz = options.delete :class
+ opts.merge! :"data-alt" => alt unless alt.blank?
+ opts.merge! "class" => clazz unless clazz.blank?
+ opts.merge! :"data-picture" => true
content = block_given? ? capture(&block) : ''
- content_tag :div, content, options
+ content_tag :div, content, opts
end
- def pic_src src, media=nil, options = {}
- options.merge! {:"data-src" => src}
+ # UGLY AS HELL!!! Needs refactor :P
+ def picture_src src, *args
+ options = args.extract_options!
+ media = args.first.to_s if args.first.kind_of?(String) || args.first.kind_of?(Fixnum)
- ratio_opt = options[:ratio]
- media = Picturefill::ViewHelper.extract media
+ ratio_opt = options.delete(:ratio)
+ media_opt = Picturefill::ViewHelper.extract media unless media.blank?
- unless media && media =~ /min-device-pixel-ratio/
+ unless media_opt && media_opt =~ /min-device-pixel-ratio/
# use filename to provide ratio_opt
- fn = filename(src) =~ /_x\d(\d)?/
+ filename = Picturefill::ViewHelper.filename(src).first
+ fn = filename =~ /_x\d(\d)?/
if fn && !ratio_opt
- ratio_opt = fn.match(/_x\d(\d)?/).to_s
- end
-
- if ratio_opt
- auto_ratio_tag = ratio[0] == 'x'
- ratio = Picturefill::ViewHelper.ratio_attrib ratio_opt if ratio_opt
+ ratio_opt = filename.match(/x\d(\d)?$/).to_s
+ else
+ auto_ratio_tag = ratio_opt[0] == 'x' unless ratio_opt.blank?
end
-
- media = [media, ratio].compact.join(' and ')
+ ratio = Picturefill::ViewHelper.ratio_attrib(ratio_opt) unless ratio_opt.blank?
+ media_opt = [media_opt, ratio].compact.join(' and ')
end
- options.merge!(:"data-media" => media)
-
- capture do
- content_tag :div, content, options
- if auto_ratio_tag
- filename = Picturefill::ViewHelper.ratio_file_name src, ratio_opt
- pic_src filename, options.merge(:ratio => ratio_opt)
- end
+ next_content = if auto_ratio_tag
+ opts = options.dup
+ filename = Picturefill::ViewHelper.ratio_file_name src, ratio_opt
+ opts.merge!(:ratio => ratio_opt.delete('x'))
+ picture_src filename, media, opts
end
+
+ options.merge! :"data-media" => media_opt unless auto_ratio_tag || media_opt.blank?
+ options.merge! :"data-src" => src
+
+ content_tag(:div, nil, options) + next_content
end
- def pic_fallback src, options = {}
- content_tag :noscript, image_tag(src, options)
+ def picture_fallback src, options = {}
+ content_tag :noscript, content_tag(:img, nil, options.merge(src: src))
end
class << self
def filename src
src_parts = src.split('.')
ext = src_parts[1..-1].join('.')
- src_parts.first
+ [src_parts.first, ext]
end
def ratio_file_name src, ratio_opt
+ fn_parts = filename(src)
ratio_opt = ratio_opt.delete('x')
- "#{filename(src)}_x2.#{ext}"
+ "#{fn_parts.first}_x2.#{fn_parts.last}"
end
def extract media
+ return if media.blank?
case media
when /^(\d+)$/
"(min-width: #{media}px)"
@@ -73,15 +80,15 @@ def extract media
end
def ratio_attrib ratio
- ratio = ratio.to_s.delete!('x')
+ ratio = ratio.to_s.delete('x')
minor = 0
case ratio.to_s
when /^\d/
major = ratio
when /^\d.\d/
major, minor = ratio.split '.'
else
- raise ArgumentError, "Invalid ratio, must be a number, fx '2.5' or '2' (even 'x2' or 'x2.5')"
+ raise ArgumentError, "Invalid ratio: #{ratio}, must be a number, fx '2.5' or '2' (even 'x2' or 'x2.5')"
end
ratio_attribute major, minor
end
@@ -0,0 +1,70 @@
+require 'spec_helper'
+
+describe Picturefill::ViewHelper do
+ include ControllerTestHelpers,
+ Picturefill::ViewHelper
+
+ describe '#picturefill' do
+ context 'no arguments' do
+ it "should be empty with a data-picture attribute" do
+ output = picturefill do
+ end
+ output.should == "<div data-picture=\"true\"></div>"
+ end
+ end
+
+ context 'alt option' do
+ it "should add the data-alt atribute" do
+ output = picturefill alt: 'nice pic' do
+ end
+ output.should == "<div data-alt=\"nice pic\" data-picture=\"true\"></div>"
+ end
+ end
+
+ context 'alt option and block' do
+ it "should add a piture src" do
+ output = picturefill alt: 'nice pic' do
+ picture_src 'small.jpg'
+ end
+ output.should == "<div data-alt=\"nice pic\" data-picture=\"true\"><div data-src=\"small.jpg\"></div></div>"
+ end
+ end
+ end
+
+ describe '#picture_src' do
+ context 'filename with media: 400' do
+ it "should add a piture src with ratio and 400px min width" do
+ output = picture_src 'small.jpg', 400
+ output.should == "<div data-media=\"(min-width: 400px)\" data-src=\"small.jpg\"></div>"
+ end
+ end
+
+ context 'filename with _x2' do
+ it "should add a piture src" do
+ output = picture_src 'small_x2.jpg'
+ output.should == "<div data-media=\"(min-device-pixel-ratio: 2.0)\" data-src=\"small_x2.jpg\"></div>"
+ end
+ end
+
+ context 'filename with _x2 and media: 400' do
+ it "should add a piture src with ratio and 400px min width" do
+ output = picture_src 'small_x2.jpg', 400
+ output.should == "<div data-media=\"(min-width: 400px) and (min-device-pixel-ratio: 2.0)\" data-src=\"small_x2.jpg\"></div>"
+ end
+ end
+
+ context "filename and ratio: 'x2'" do
+ it "should add an extra piture src for Retina with x2" do
+ output = picture_src 'small.jpg', ratio: 'x2'
+ output.should == "<div data-src=\"small.jpg\"></div><div data-media=\"(min-device-pixel-ratio: 2.0)\" data-src=\"small_x2.jpg\"></div>"
+ end
+ end
+ end
+
+ describe '#pic_fallback' do
+ it "should add a <noscript> fallback with a normal <img> tag as fallback" do
+ output = picture_fallback 'small.jpg'
+ output.should == "<noscript><img src=\"small.jpg\"></img></noscript>"
+ end
+ end
+end
View
@@ -1,12 +1,46 @@
-$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
-$LOAD_PATH.unshift(File.dirname(__FILE__))
+# coding: utf-8
+require 'rubygems'
+require 'rails'
+require 'json'
+require 'active_support'
+require 'action_pack'
+require 'action_view'
+require 'action_controller'
+require 'action_view/template'
+
require 'rspec'
require 'picturefill-rails'
-# Requires supporting files with custom matchers and macros, etc,
-# in ./support/ and its subdirectories.
-Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
+# WorldFlags::Rails::Engine.add_view_ext
+
+SPEC_DIR = File.dirname(__FILE__)
+
+module ControllerTestHelpers
-RSpec.configure do |config|
+ def self.included(base)
+ base.class_eval do
+
+ include ActionView::Helpers,
+ ActionView::Helpers::CaptureHelper,
+ ActionView::Helpers::JavaScriptHelper,
+ ActionView::Helpers::AssetTagHelper
+ # allow tabs.create to run by stubbing an output_buffer
+ attr_accessor :output_buffer
+ @output_buffer = ""
+
+ # stub content_for for testing
+ def content_for(name, content = nil, &block)
+ # this doesn't exist, and causes errors
+ @_content_for = {} unless defined? @_content_for
+ # we've got to initialize this, so we can concat to it
+ @_content_for[name] = '' if @_content_for[name].nil?
+ # now the rest is the same as in rails
+ content = capture(&block) if block_given?
+ @_content_for[name] << content if content
+ @_content_for[name] unless content
+ end
+ end
+ end
+
end

0 comments on commit 5aa937d

Please sign in to comment.