├── .document ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── LICENSE.txt ├── README.md ├── Rakefile ├── VERSION ├── headjs-rails.gemspec ├── lib ├── generators │ └── headjs │ │ └── install │ │ └── install_generator.rb ├── headjs-rails.rb └── headjs-rails │ └── tag_helper.rb └── test ├── helper.rb ├── public └── javascripts │ ├── jquery.js │ └── rails.js ├── test_generator.rb └── test_tag_helper.rb /.document: -------------------------------------------------------------------------------- 1 | lib/**/*.rb 2 | bin/* 3 | - 4 | features/**/*.feature 5 | LICENSE.txt 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # rcov generated 2 | coverage 3 | 4 | # rdoc generated 5 | rdoc 6 | 7 | # yard generated 8 | doc 9 | .yardoc 10 | 11 | # bundler 12 | .bundle 13 | 14 | # jeweler generated 15 | pkg 16 | 17 | log 18 | .ruby-version 19 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gem "rails", ">= 3.0.0" 4 | 5 | group :development do 6 | gem "shoulda" 7 | gem "bundler" 8 | gem "jeweler" 9 | end 10 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | actionmailer (3.2.8) 5 | actionpack (= 3.2.8) 6 | mail (~> 2.4.4) 7 | actionpack (3.2.8) 8 | activemodel (= 3.2.8) 9 | activesupport (= 3.2.8) 10 | builder (~> 3.0.0) 11 | erubis (~> 2.7.0) 12 | journey (~> 1.0.4) 13 | rack (~> 1.4.0) 14 | rack-cache (~> 1.2) 15 | rack-test (~> 0.6.1) 16 | sprockets (~> 2.1.3) 17 | activemodel (3.2.8) 18 | activesupport (= 3.2.8) 19 | builder (~> 3.0.0) 20 | activerecord (3.2.8) 21 | activemodel (= 3.2.8) 22 | activesupport (= 3.2.8) 23 | arel (~> 3.0.2) 24 | tzinfo (~> 0.3.29) 25 | activeresource (3.2.8) 26 | activemodel (= 3.2.8) 27 | activesupport (= 3.2.8) 28 | activesupport (3.2.8) 29 | i18n (~> 0.6) 30 | multi_json (~> 1.0) 31 | arel (3.0.2) 32 | builder (3.0.4) 33 | erubis (2.7.0) 34 | git (1.2.5) 35 | hike (1.2.1) 36 | i18n (0.6.1) 37 | jeweler (1.8.4) 38 | bundler (~> 1.0) 39 | git (>= 1.2.5) 40 | rake 41 | rdoc 42 | journey (1.0.4) 43 | json (1.7.5) 44 | mail (2.4.4) 45 | i18n (>= 0.4.0) 46 | mime-types (~> 1.16) 47 | treetop (~> 1.4.8) 48 | mime-types (1.19) 49 | multi_json (1.3.7) 50 | polyglot (0.3.3) 51 | rack (1.4.1) 52 | rack-cache (1.2) 53 | rack (>= 0.4) 54 | rack-ssl (1.3.2) 55 | rack 56 | rack-test (0.6.2) 57 | rack (>= 1.0) 58 | rails (3.2.8) 59 | actionmailer (= 3.2.8) 60 | actionpack (= 3.2.8) 61 | activerecord (= 3.2.8) 62 | activeresource (= 3.2.8) 63 | activesupport (= 3.2.8) 64 | bundler (~> 1.0) 65 | railties (= 3.2.8) 66 | railties (3.2.8) 67 | actionpack (= 3.2.8) 68 | activesupport (= 3.2.8) 69 | rack-ssl (~> 1.3.2) 70 | rake (>= 0.8.7) 71 | rdoc (~> 3.4) 72 | thor (>= 0.14.6, < 2.0) 73 | rake (0.9.2.2) 74 | rdoc (3.12) 75 | json (~> 1.4) 76 | shoulda (3.3.2) 77 | shoulda-context (~> 1.0.1) 78 | shoulda-matchers (~> 1.4.1) 79 | shoulda-context (1.0.1) 80 | shoulda-matchers (1.4.1) 81 | activesupport (>= 3.0.0) 82 | sprockets (2.1.3) 83 | hike (~> 1.2) 84 | rack (~> 1.0) 85 | tilt (~> 1.1, != 1.3.0) 86 | thor (0.16.0) 87 | tilt (1.3.3) 88 | treetop (1.4.12) 89 | polyglot 90 | polyglot (>= 0.3.1) 91 | tzinfo (0.3.35) 92 | 93 | PLATFORMS 94 | ruby 95 | x86-mingw32 96 | 97 | DEPENDENCIES 98 | bundler 99 | jeweler 100 | rails (>= 3.0.0) 101 | shoulda 102 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 David Bittencourt 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # headjs-rails 2 | 3 | This gem adds a helper and a generator to facilitate the use of [Head JS](http://headjs.com) in your Rails 3 projects, the same way you would normally add javascript tags using Rails `javascript_include_tag` helper. 4 | 5 | ## Usage 6 | 7 | In your Gemfile, add this line: 8 | 9 | gem "headjs-rails" 10 | 11 | Then, run `bundle install`. To invoke the generator and install the latest Head JS files in your `public/javascripts` folder, run: 12 | 13 | rails generate headjs:install 14 | 15 | Now just add headjs to your head, using default rails `javascript_include_tag('head.min')` for example, and put the rest of your scripts at the bottom of your layout with the `headjs_include_tag` method the gem provides. This method is a wrapper of `javascript_include_tag` and accepts the exact same methods, so it should work fine with any other gem/plugin that works with it. 16 | 17 | headjs_include_tag(:defaults) 18 | headjs_include_tag(:all) 19 | headjs_include_tag('http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js') 20 | headjs_include_tag('jquery', 'jquery.ui', 'jquery.plugin', 'rails') 21 | headjs_include_tag(:defaults, :cache => true) 22 | headjs_include_tag(:defaults, 'jquery.ui', :cache => 'bundle') 23 | 24 | The sources will have labels automatically assigned based on the filename (removing .js, .min.js and any other parameter). 25 | 26 | headjs_include_tag('jquery', 'rails') 27 | # 28 | 29 | headjs_include_tag(:defaults, :cache => 'bundle') 30 | # 31 | 32 | Don't forget to use `head.ready()` in any code that runs inside your views. More information in [Head JS API](http://headjs.com/#api). 33 | 34 | I also suggest you take a look at the [smurf gem](https://github.com/thumblemonks/smurf), a drop-in gem that automatically minifies Javascript (and CSS) when you use caching and rails default include tag helpers. It works fine with `headjs_include_tag` as well as it's just a wrapper of `javascript_include_tag`. 35 | 36 | ## Testing 37 | 38 | Clone the repo, run `bundle install` and `bundle exec rake test`. 39 | 40 | ## Contributing to headjs-rails 41 | 42 | Fork the project and send pull requests. 43 | 44 | ## Copyright 45 | 46 | Author: David Bittencourt. See LICENSE.txt for further details. 47 | 48 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | begin 4 | Bundler.setup(:default, :development) 5 | rescue Bundler::BundlerError => e 6 | $stderr.puts e.message 7 | $stderr.puts "Run `bundle install` to install missing gems" 8 | exit e.status_code 9 | end 10 | require 'rake' 11 | 12 | require 'jeweler' 13 | Jeweler::Tasks.new do |gem| 14 | # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options 15 | gem.name = "headjs-rails" 16 | gem.homepage = "http://github.com/muitocomplicado/headjs-rails" 17 | gem.license = "MIT" 18 | gem.summary = %Q{Provides Rails 3 helper and generator for adding Head JS support.} 19 | gem.description = %Q{This gem adds a helper and generator to facilitate the use of Head JS in your Rails 3 projects the same way you would normally add javascript tags using Rails default helpers.} 20 | gem.email = "muitocomplicado@gmail.com" 21 | gem.authors = ["David Bittencourt"] 22 | end 23 | Jeweler::RubygemsDotOrgTasks.new 24 | 25 | require 'rake/testtask' 26 | Rake::TestTask.new(:test) do |test| 27 | test.libs << 'lib' << 'test' 28 | test.pattern = 'test/**/test_*.rb' 29 | test.verbose = true 30 | end 31 | 32 | task :default => :test 33 | 34 | require 'rdoc/task' 35 | Rake::RDocTask.new do |rdoc| 36 | version = File.exist?('VERSION') ? File.read('VERSION') : "" 37 | 38 | rdoc.rdoc_dir = 'rdoc' 39 | rdoc.title = "headjs-rails #{version}" 40 | rdoc.rdoc_files.include('README*') 41 | rdoc.rdoc_files.include('lib/**/*.rb') 42 | end 43 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.4.2 -------------------------------------------------------------------------------- /headjs-rails.gemspec: -------------------------------------------------------------------------------- 1 | # Generated by jeweler 2 | # DO NOT EDIT THIS FILE DIRECTLY 3 | # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' 4 | # -*- encoding: utf-8 -*- 5 | 6 | Gem::Specification.new do |s| 7 | s.name = "headjs-rails" 8 | s.version = "0.4.2" 9 | 10 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= 11 | s.authors = ["David Bittencourt"] 12 | s.date = "2013-11-19" 13 | s.description = "This gem adds a helper and generator to facilitate the use of Head JS in your Rails 3 projects the same way you would normally add javascript tags using Rails default helpers." 14 | s.email = "muitocomplicado@gmail.com" 15 | s.extra_rdoc_files = [ 16 | "LICENSE.txt", 17 | "README.md" 18 | ] 19 | s.files = [ 20 | ".document", 21 | "Gemfile", 22 | "Gemfile.lock", 23 | "LICENSE.txt", 24 | "README.md", 25 | "Rakefile", 26 | "VERSION", 27 | "headjs-rails.gemspec", 28 | "lib/generators/headjs/install/install_generator.rb", 29 | "lib/headjs-rails.rb", 30 | "lib/headjs-rails/tag_helper.rb", 31 | "test/helper.rb", 32 | "test/public/javascripts/jquery.js", 33 | "test/public/javascripts/rails.js", 34 | "test/test_generator.rb", 35 | "test/test_tag_helper.rb" 36 | ] 37 | s.homepage = "http://github.com/muitocomplicado/headjs-rails" 38 | s.licenses = ["MIT"] 39 | s.require_paths = ["lib"] 40 | s.rubygems_version = "1.8.23" 41 | s.summary = "Provides Rails 3 helper and generator for adding Head JS support." 42 | 43 | if s.respond_to? :specification_version then 44 | s.specification_version = 3 45 | 46 | if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then 47 | s.add_runtime_dependency(%q, [">= 3.0.0"]) 48 | s.add_development_dependency(%q, [">= 0"]) 49 | s.add_development_dependency(%q, [">= 0"]) 50 | s.add_development_dependency(%q, [">= 0"]) 51 | else 52 | s.add_dependency(%q, [">= 3.0.0"]) 53 | s.add_dependency(%q, [">= 0"]) 54 | s.add_dependency(%q, [">= 0"]) 55 | s.add_dependency(%q, [">= 0"]) 56 | end 57 | else 58 | s.add_dependency(%q, [">= 3.0.0"]) 59 | s.add_dependency(%q, [">= 0"]) 60 | s.add_dependency(%q, [">= 0"]) 61 | s.add_dependency(%q, [">= 0"]) 62 | end 63 | end 64 | 65 | -------------------------------------------------------------------------------- /lib/generators/headjs/install/install_generator.rb: -------------------------------------------------------------------------------- 1 | require "openssl" 2 | module OpenSSL 3 | module SSL 4 | remove_const :VERIFY_PEER 5 | end 6 | end 7 | OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE 8 | 9 | module Headjs 10 | module Generators 11 | class InstallGenerator < ::Rails::Generators::Base 12 | desc "This generator downloads and installs Head JS" 13 | class_option :version, :type => :string, :default => "1.0.0", :desc => "Which version of Head JS to fetch" 14 | @@default_version = "1.0.0" 15 | @@dist_url = "https://raw.github.com/headjs/headjs/master/dist/{version}/{file}" 16 | 17 | def remove_headjs 18 | %w(head.js head.min.js).each do |js| 19 | remove_file "public/javascripts/#{js}" 20 | end 21 | end 22 | 23 | def download_headjs 24 | say_status("fetching", "Head JS (#{options.version})", :green) 25 | get_headjs(options.version) 26 | rescue OpenURI::HTTPError 27 | say_status("warning", "could not find Head JS (#{options.version})", :yellow) 28 | say_status("warning", headjs_url(options.version, 'head.js'), :yellow) 29 | say_status("warning", headjs_url(options.version, 'head.min.js'), :yellow) 30 | 31 | if @@default_version != options.version 32 | say_status("fetching", "Head JS (#{@@default_version})", :green) 33 | get_headjs(@@default_version) 34 | end 35 | end 36 | 37 | private 38 | 39 | def get_headjs(version) 40 | %w(head.js head.min.js).each do |js| 41 | get headjs_url(version, js), "public/javascripts/#{js}" 42 | end 43 | end 44 | 45 | def headjs_url(version, file) 46 | @@dist_url.gsub("{version}", version).gsub("{file}", file) 47 | end 48 | 49 | end 50 | end 51 | end -------------------------------------------------------------------------------- /lib/headjs-rails.rb: -------------------------------------------------------------------------------- 1 | require File.join(File.dirname(__FILE__), 'headjs-rails', 'tag_helper') 2 | 3 | ActionController::Base.helper(Headjs::TagHelper) -------------------------------------------------------------------------------- /lib/headjs-rails/tag_helper.rb: -------------------------------------------------------------------------------- 1 | module Headjs 2 | 3 | module TagHelper 4 | 5 | def headjs_include_tag(*sources) 6 | content_tag :script, { :type => Mime::JS }, false do 7 | headjs_include_js(*sources) 8 | end 9 | end 10 | 11 | def headjs_include_js(*sources) 12 | "head.js( #{headjs_include_params(*sources)} );".html_safe 13 | end 14 | 15 | def headjs_include_params(*sources) 16 | keys = [] 17 | javascript_include_tag(*sources). 18 | scan(/src="([^"]+)"/). 19 | flatten. 20 | map do |src| 21 | cnt = 0 22 | key = original_key = 23 | URI. 24 | parse(src). 25 | path[%r{[^/]+\z}]. 26 | gsub(/\.js$/,''). 27 | gsub(/\.min$/,''). 28 | gsub(/-[0-9a-f]{32}$/,'') 29 | while keys.include?(key) do 30 | key = "#{original_key}_#{(cnt = cnt.succ)}" 31 | end 32 | keys << key 33 | "{ '#{key}': '#{src}' }" 34 | end.join(', ').html_safe 35 | end 36 | 37 | end 38 | 39 | end 40 | -------------------------------------------------------------------------------- /test/helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | begin 4 | Bundler.setup(:default, :development) 5 | rescue Bundler::BundlerError => e 6 | $stderr.puts e.message 7 | $stderr.puts "Run `bundle install` to install missing gems" 8 | exit e.status_code 9 | end 10 | 11 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 12 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 13 | 14 | require 'rails/all' 15 | require 'shoulda' 16 | require 'rails/test_help' 17 | require 'rails/generators' 18 | require 'headjs-rails' 19 | 20 | -------------------------------------------------------------------------------- /test/public/javascripts/jquery.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muitocomplicado/headjs-rails/97903ac4b998a4ad06168bb3514fc67db528ce23/test/public/javascripts/jquery.js -------------------------------------------------------------------------------- /test/public/javascripts/rails.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muitocomplicado/headjs-rails/97903ac4b998a4ad06168bb3514fc67db528ce23/test/public/javascripts/rails.js -------------------------------------------------------------------------------- /test/test_generator.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | require 'generators/headjs/install/install_generator' 3 | 4 | class Headjs::Generators::InstallGeneratorTest < Rails::Generators::TestCase 5 | tests Headjs::Generators::InstallGenerator 6 | destination File.join(File.dirname(__FILE__), 'tmp') 7 | teardown :cleanup_destination_root 8 | 9 | context 'the Head JS install generator' do 10 | 11 | should 'download the default 1.0.0 files' do 12 | run_generator %w(headjs:install) 13 | assert_file 'public/javascripts/head.js' 14 | assert_file 'public/javascripts/head.min.js' 15 | end 16 | 17 | should 'download version 0.99 files' do 18 | run_generator %w(headjs:install --version 0.99) 19 | assert_file 'public/javascripts/head.js' 20 | assert_file 'public/javascripts/head.min.js' 21 | end 22 | 23 | end 24 | 25 | private 26 | 27 | def cleanup_destination_root 28 | FileUtils.rm_r(destination_root) 29 | end 30 | 31 | end -------------------------------------------------------------------------------- /test/test_tag_helper.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | module Headjs 4 | 5 | class TagHelperTest < Test::Unit::TestCase 6 | 7 | def setup 8 | 9 | ENV["RAILS_ASSET_ID"] = '' 10 | ActionView::Helpers::AssetTagHelper.register_javascript_expansion :defaults => %w(jquery rails) 11 | 12 | public_dir = File.join(File.dirname(__FILE__), 'public') 13 | @helpers = ActionController::Base.helpers 14 | @helpers.config.perform_caching = false 15 | @helpers.config.assets_dir = public_dir 16 | @helpers.config.javascripts_dir = "#{public_dir}/javascripts" 17 | 18 | %w(all.js bundle.js).each do |js| 19 | begin 20 | File.delete(File.join(public_dir, 'javascripts', js)) 21 | rescue 22 | end 23 | end 24 | 25 | end 26 | 27 | def jquery 28 | 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js' 29 | end 30 | 31 | context "The Head JS helper include tag" do 32 | 33 | should "return a valid script tag" do 34 | assert_equal "", @helpers.headjs_include_tag(jquery) 35 | end 36 | 37 | should "increase label counter to avoid overwriting" do 38 | assert_equal "", @helpers.headjs_include_tag('products/comments', 'reviews/comments') 39 | end 40 | 41 | should "accept strings for local paths" do 42 | assert_equal "", @helpers.headjs_include_tag('jquery', 'other/rails') 43 | end 44 | 45 | should "accept :defaults registered expansions" do 46 | assert_equal "", @helpers.headjs_include_tag(:defaults) 47 | end 48 | 49 | should "accept :defaults mixed with other strings" do 50 | assert_equal "", @helpers.headjs_include_tag(:defaults, 'modernizr') 51 | end 52 | 53 | should "accept :all expansion" do 54 | assert_equal "", @helpers.headjs_include_tag(:all) 55 | end 56 | 57 | should "accept a :cache => true parameter" do 58 | @helpers.config.perform_caching = true 59 | assert_equal "", @helpers.headjs_include_tag(:defaults, :cache => true) 60 | end 61 | 62 | should "accept a :cache => bundle parameter" do 63 | @helpers.config.perform_caching = true 64 | assert_equal "", @helpers.headjs_include_tag(:defaults, :cache => 'bundle') 65 | end 66 | 67 | should "work with random rails asset ids" do 68 | ENV["RAILS_ASSET_ID"] = '123456789' 69 | assert_equal "", @helpers.headjs_include_tag(:defaults) 70 | end 71 | 72 | should "remove rails asset hashes" do 73 | assert_equal "", @helpers.headjs_include_tag('/assets/foo-f1d2d2f924e986ac86fdf7b36c94bcdf.js') 74 | end 75 | 76 | end 77 | 78 | end 79 | 80 | end 81 | --------------------------------------------------------------------------------