handlebone 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/.document +5 -0
  2. data/Gemfile +16 -0
  3. data/Guardfile +18 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.markdown +58 -0
  6. data/Rakefile +67 -0
  7. data/VERSION +1 -0
  8. data/generators/backbone_view/backbone_view_generator.rb +9 -0
  9. data/generators/backbone_view/templates/view.coffee.erb +2 -0
  10. data/generators/backbone_view/templates/view_template.html.handlebars +2 -0
  11. data/lib/assets/javascripts/handlebars_helpers.coffee +46 -0
  12. data/lib/assets/javascripts/handlebars_view.coffee +26 -0
  13. data/lib/generators/backbone/USAGE +8 -0
  14. data/lib/generators/backbone/backbone_generator.rb +6 -0
  15. data/lib/handlebone.rb +5 -0
  16. data/lib/handlebone/engine.rb +9 -0
  17. data/lib/handlebone/helper.rb +13 -0
  18. data/rakelib/coffeescript.rake +30 -0
  19. data/spec/javascripts/fixtures/child_view.handlebars.html +4 -0
  20. data/spec/javascripts/fixtures/multiple_child_parent_view.handlebars.html +7 -0
  21. data/spec/javascripts/fixtures/parent_view.handlebars.html +6 -0
  22. data/spec/javascripts/fixtures/simple_view.handlebars.html +4 -0
  23. data/spec/javascripts/handlebars_view_spec.coffee +55 -0
  24. data/spec/javascripts/helpers/SpecHelper.js +9 -0
  25. data/spec/javascripts/helpers/loadTemplateHelper.js +17 -0
  26. data/spec/javascripts/jasmine-jquery-1.1.3.js +205 -0
  27. data/spec/javascripts/jquery.js +167 -0
  28. data/spec/javascripts/support/jasmine.yml +78 -0
  29. data/spec/javascripts/support/jasmine_config.rb +23 -0
  30. data/spec/javascripts/support/jasmine_runner.rb +32 -0
  31. data/test/helper.rb +18 -0
  32. data/test/test_backbone-handlebars.rb +7 -0
  33. data/vendor/assets/javascripts/backbone.js +1066 -0
  34. data/vendor/assets/javascripts/handlebars.js +1417 -0
  35. data/vendor/assets/javascripts/underscore.js +748 -0
  36. metadata +164 -0
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.6.0"
12
+ gem "rcov", ">= 0"
13
+ gem "jasmine"
14
+ gem "coffee-script"
15
+ gem "guard-coffeescript"
16
+ end
@@ -0,0 +1,18 @@
1
+ # A sample Guardfile
2
+ # More info at http://github.com/guard/guard#readme
3
+ #
4
+ # Guard is a tool to respond to local filesystem events and take action. As such, it works better using native filesystem event libraries
5
+ #
6
+ # 1. Setup an RVM 1.9.2 environment to run guard
7
+ # 2. gem install guard-coffeescript growl rb-fsevent
8
+ # 3. run the 'guard' command; this fires up a server to monitor the coffescript as shown below
9
+ # 4. C-\ will force guard to recompile everything it knows about
10
+ # 5. Install the Gowl "Extras" growlnotify
11
+
12
+ guard 'coffeescript', :output => 'javascripts/compiled' do
13
+ watch(%r{lib/assets/javascripts/.+\.coffee})
14
+ end
15
+
16
+ guard 'coffeescript', :output => 'spec/javascripts/compiled', :bare => true do
17
+ watch(%r{spec/javascripts/.*_spec\.coffee})
18
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Chris Nelson
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.
@@ -0,0 +1,58 @@
1
+ handlebone
2
+ ===================
3
+
4
+ This gem is extracted out of a backbone project where we are using handlebars
5
+ templates. It contains:
6
+
7
+ * handlebars.js
8
+ * A HandlebarsView superclass
9
+ * a rails helper module for rendering all your handlebars templates into your rails view
10
+ * Some handlebars helpers to make things easier
11
+
12
+ Usage
13
+ =====
14
+
15
+ This gem is designed to integrate with the asset pipeline of rails 3.1+. Somewhere in your
16
+ coffeescript or javascript code you'll need to require it:
17
+
18
+ #= require handlebars_view
19
+
20
+ This will bring in handlebars and the view superclass. To use it, write a view like so:
21
+
22
+ class FooView extends HandlebarsView
23
+
24
+ name: "foo_view"
25
+
26
+ This will cause the view to look for a template in an element with id "foo_view_template" and use
27
+ handlebars to render this view, passing in the view's model as the template
28
+ context. You can change this by overriding the templateContext function in your view.
29
+
30
+ HandlebarsHelpers
31
+ =================
32
+
33
+ Some helper methods to make writing those templates easier.
34
+
35
+ {{get "property"}}
36
+
37
+ This will grab a property from the model that is the current context
38
+
39
+ {{#eachProperty "children"}}hi!{{/eachProperty}}
40
+
41
+ A block helper that iterates over a property that contains an array.
42
+
43
+ Somewhere in your DOM ready, you'll need to call registerHelpers. Like so:
44
+
45
+ $ -> Backbone.HandlebarsHelpers.registerHelpers()
46
+
47
+ Also, you can register your own helpers by passing an object where each propery is a method that will
48
+ become a helper
49
+
50
+ Backbone.HandlebarsHelpers.registerHelpers(new MyHelpers())
51
+
52
+ RenderTemplatesHelper
53
+ ======================
54
+
55
+ We've found it best practice to keep our handlebars templates in separate files so our rails
56
+ views don't get all noisy. This all let's use the same HandleBars view on more than one rails
57
+ view and in our jasmine specs. This gem also includes a rails helper module RenderTemplatesHelper.
58
+ Best to just look at the code to see what it does for now, it's super simple.
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "handlebone"
18
+ gem.homepage = "http://github.com/gaslightsoftware/handlebone"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Backbone views with handlebars templates}
21
+ gem.description = %Q{That's all folks}
22
+ gem.email = "superchrisnelson@gmail.com"
23
+ gem.authors = ["Chris Nelson"]
24
+ gem.files.include "vendor/assets/**/*"
25
+ gem.files.include "lib/**/*"
26
+ # dependencies defined in Gemfile
27
+ end
28
+ Jeweler::RubygemsDotOrgTasks.new
29
+
30
+ require 'rake/testtask'
31
+ Rake::TestTask.new(:test) do |test|
32
+ test.libs << 'lib' << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+
37
+ require 'rcov/rcovtask'
38
+ Rcov::RcovTask.new do |test|
39
+ test.libs << 'test'
40
+ test.pattern = 'test/**/test_*.rb'
41
+ test.verbose = true
42
+ test.rcov_opts << '--exclude "gems/*"'
43
+ end
44
+
45
+ task :default => :test
46
+
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "handlebone #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
56
+
57
+ begin
58
+ require 'jasmine'
59
+ load 'jasmine/tasks/jasmine.rake'
60
+ rescue LoadError
61
+ task :jasmine do
62
+ abort "Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine"
63
+ end
64
+ end
65
+
66
+
67
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,9 @@
1
+ class BackboneViewGenerator < Rails::Generator::NamedBase
2
+
3
+ def manifest
4
+ record do |m|
5
+ m.template "view.coffee.erb", "backbone/views/#{name}.coffee", :assigns => {:name => name}
6
+ m.template "view_template.html.handlebars", "backbone/templates/#{name}.html.handlebars", :assigns => {:name => name}
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ class <%= name.camelize %> extends TemplateView
2
+ name: "<%= name %>"
@@ -0,0 +1,2 @@
1
+ <script id="<%=name%>_template" type="text/html">
2
+ </script>
@@ -0,0 +1,46 @@
1
+ class Backbone.HandlebarsHelpers
2
+
3
+ is: (block) ->
4
+ hash = block.hash
5
+ block() if this[hash.property] == hash.value
6
+
7
+ stripe: (collection, block) ->
8
+ item_contents = for index in [0...collection.length]
9
+ collection[index].stripeClass = if ((index % 2) == 0) then "even" else "odd"
10
+ block collection[index]
11
+ item_contents.join("\n")
12
+
13
+ formatNumber: (number) ->
14
+ $.formatNumber number, {format: "#,###"}
15
+
16
+ formatCurrency: (number) ->
17
+ $.formatNumber number, {format: "$#,###.00"}
18
+
19
+ formatPercentage: (number) ->
20
+ formatted = $.formatNumber number, {format: "#,###.0000"}
21
+ "#{formatted}%"
22
+
23
+ get: (property)->
24
+ @get(property)
25
+
26
+ helperMissing: -> ""
27
+
28
+ eachProperty: (property, block)->
29
+ block(object) for object in @get(property)
30
+
31
+ view: (block) ->
32
+ params = block.hash
33
+ view = block.data.view
34
+ viewClass = eval(params.viewClass)
35
+ if params.modelClass
36
+ modelClass = eval(params.modelClass)
37
+ model = new modelClass(this)
38
+ else
39
+ model = this
40
+ childView = new viewClass(model: model, parent: view)
41
+ view.subViews.push childView
42
+ block(model)
43
+
44
+ @registerHelpers: (helpers)->
45
+ helpers or= new HandlebarsHelpers()
46
+ Handlebars.registerHelper name, helper for name, helper of helpers
@@ -0,0 +1,26 @@
1
+ #= require handlebars
2
+ class Backbone.HandlebarsView extends Backbone.View
3
+ constructor: (options = {})->
4
+ @el = $("##{@name}") unless options.el
5
+ @subViews = []
6
+ @parent = options.parent
7
+ super
8
+ templateEl = $("##{@name}_template")
9
+ console.log "Did you include the template for #{@name}, putz?" if console? && templateEl.size() == 0
10
+ @template = if templateEl.size() > 0 then Handlebars.compile(templateEl.html(), true) else -> ""
11
+
12
+ templateContext: ->
13
+ @model
14
+
15
+ render: ->
16
+ @subViews = []
17
+ @el.html @template @templateContext(), Handlebars.helpers, Handlebars.partials, {view: this}
18
+ @renderSubView(subView) for subView in @subViews
19
+
20
+ findEl: ->
21
+ @el = $("[data-id='#{@model.id}']")
22
+
23
+ renderSubView: (subView) ->
24
+ subView.findEl()
25
+ subView.delegateEvents()
26
+ subView.render()
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate backbone Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,6 @@
1
+ class BackboneGenerator < Rails::Generators::NamedBase
2
+ source_root File.expand_path('../templates', __FILE__)
3
+ def create_backbone_directories
4
+ empty_directory "backbone"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ if Rails.version =~ /^3/
2
+ require 'rails'
3
+ require 'handlebone/engine'
4
+ require 'handlebone/helper'
5
+ end
@@ -0,0 +1,9 @@
1
+ require 'rails'
2
+
3
+ module Handlebone
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
9
+
@@ -0,0 +1,13 @@
1
+ module Handlebone
2
+ module RenderTemplatesHelper
3
+ def render_backbone_template(template)
4
+ raw File.read(::Rails.root.join "app", "assets", "templates", "#{template}.handlebars.html")
5
+ end
6
+
7
+ def render_backbone_templates
8
+ template_directory = ::Rails.root.join "app", "assets", "templates", "*.handlebars.html"
9
+ templates = Dir.glob(template_directory).collect { |t| File.read t }
10
+ raw templates.join("\n")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ namespace :coffeescript do
2
+
3
+ def compile_files(files, output_dir)
4
+ require 'coffee-script'
5
+ files.each do |f|
6
+ new_f = File.join(output_dir, f.pathmap("%n").match(/^([^.]+)/).to_s + ".js")
7
+ File.open(new_f, "w") do |out|
8
+ puts "compiling #{f} to #{new_f}"
9
+ out.puts CoffeeScript.compile File.read(f)
10
+ end
11
+ end
12
+ end
13
+
14
+ namespace :compile do
15
+ desc "re-compile the coffeescript into javascript"
16
+ task :assets do
17
+ coffee_files = FileList["lib/assets/javascripts/*.coffee" ]
18
+ mkdir_p "javascripts/compiled"
19
+ compile_files(coffee_files, "javascripts/compiled")
20
+ end
21
+
22
+ desc "re-compile the spec coffeescript into javascript"
23
+ task :specs do
24
+ mkdir_p "spec/javascripts/compiled"
25
+ compile_files(FileList["spec/javascripts/*.coffee"], "spec/javascripts/compiled")
26
+ end
27
+ end
28
+
29
+ task :compile => ["compile:assets", "compile:specs"]
30
+ end
@@ -0,0 +1,4 @@
1
+ <script id="child_view_template" type="text/x-handlebars-template">
2
+ Foo!
3
+ </script>
4
+
@@ -0,0 +1,7 @@
1
+ <script id="multiple_child_parent_view_template" type="text/x-handlebars-template">
2
+ {{#eachProperty "children"}}
3
+ {{#view viewClass="SimpleView"}}
4
+ <div data-id="{{id}}"></div>
5
+ {{/view}}
6
+ {{/eachProperty}}
7
+ </script>
@@ -0,0 +1,6 @@
1
+ <script id="parent_view_template" type="text/x-handlebars-template">
2
+ {{#view viewClass="ChildView"}}
3
+ <div id="child"></div>
4
+ {{/view}}
5
+ </script>
6
+
@@ -0,0 +1,4 @@
1
+ <script id="simple_view_template" type="text/x-handlebars-template">
2
+ <h1>{{get "foo"}}</h1>
3
+ </script>
4
+
@@ -0,0 +1,55 @@
1
+
2
+ class SimpleView extends Backbone.HandlebarsView
3
+ name: "simple_view"
4
+
5
+ class window.ParentView extends Backbone.HandlebarsView
6
+ name: "parent_view"
7
+
8
+ class window.ChildView extends Backbone.HandlebarsView
9
+ name: "child_view"
10
+ findEl: -> @el = $("#child")
11
+
12
+ class window.MultipleChildParentView extends Backbone.HandlebarsView
13
+ name: "multiple_child_parent_view"
14
+
15
+ class window.SimpleModel extends Backbone.Model
16
+
17
+ describe "HandlebarsView", ->
18
+ beforeEach ->
19
+ Backbone.HandlebarsHelpers.registerHelpers()
20
+ describe "SimpleView", ->
21
+ beforeEach ->
22
+ setFixtures "<div id='simple_view'></div>"
23
+ loadTemplate "simple_view.handlebars.html"
24
+ @simpleView = new SimpleView(model: new SimpleModel(foo: "bar"))
25
+ @simpleView.render()
26
+ it "finds it's el", ->
27
+ expect(@simpleView.el).toExist()
28
+ it "can render model data", ->
29
+ expect(@simpleView.el.html()).toMatch /bar/
30
+
31
+ describe "subviews", ->
32
+ beforeEach ->
33
+ setFixtures "<div id='parent_view'></div>"
34
+ loadTemplate "parent_view.handlebars.html"
35
+ loadTemplate "child_view.handlebars.html"
36
+ @parentView = new ParentView(model: new SimpleModel(id: 1))
37
+ @parentView.render()
38
+ it "renders the child template too", ->
39
+ expect(@parentView.el.html()).toMatch /Foo/
40
+ it "has a child view as a subviews", ->
41
+ expect(@parentView.subViews.length).toEqual(1)
42
+
43
+ describe "multiple child views", ->
44
+ beforeEach ->
45
+ setFixtures "<div id='multiple_child_parent_view'></div>"
46
+ loadTemplate "multiple_child_parent_view.handlebars.html"
47
+ loadTemplate "simple_view.handlebars.html"
48
+ children = [new SimpleModel(id: 1, foo: "baz"), new SimpleModel(id: 2, foo: "bing")]
49
+ @multipleChildParentView = new MultipleChildParentView(model: new SimpleModel(children: children))
50
+ @multipleChildParentView.render()
51
+ it "renders children views", ->
52
+ expect(@multipleChildParentView.el.html()).toMatch /baz/
53
+ expect(@multipleChildParentView.el.html()).toMatch /bing/
54
+
55
+