manatee 0.0.1.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +23 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.mdown +55 -0
  5. data/Rakefile +7 -0
  6. data/app/assets/javascripts/manatee.js +1 -0
  7. data/app/assets/javascripts/manatee/helpers.js +4 -0
  8. data/app/assets/javascripts/manatee/helpers/asset_tag.jsh.coffee +138 -0
  9. data/app/assets/javascripts/manatee/helpers/asset_url.jsh.coffee +90 -0
  10. data/app/assets/javascripts/manatee/helpers/csrf.jsh.coffee +5 -0
  11. data/app/assets/javascripts/manatee/helpers/date.jsh.coffee +54 -0
  12. data/app/assets/javascripts/manatee/helpers/debug.jsh.coffee +2 -0
  13. data/app/assets/javascripts/manatee/helpers/form.jsh.coffee +25 -0
  14. data/app/assets/javascripts/manatee/helpers/form_builder.jsh.coffee +24 -0
  15. data/app/assets/javascripts/manatee/helpers/form_options.jsh.coffee +267 -0
  16. data/app/assets/javascripts/manatee/helpers/form_tag.jsh.coffee +204 -0
  17. data/app/assets/javascripts/manatee/helpers/javascript.jsh.coffee +15 -0
  18. data/app/assets/javascripts/manatee/helpers/number.jsh.coffee +58 -0
  19. data/app/assets/javascripts/manatee/helpers/sanitize.jsh.coffee +5 -0
  20. data/app/assets/javascripts/manatee/helpers/tag.jsh.coffee +58 -0
  21. data/app/assets/javascripts/manatee/helpers/text.jsh.coffee +12 -0
  22. data/app/assets/javascripts/manatee/helpers/translation.jsh.coffee +7 -0
  23. data/app/assets/javascripts/manatee/helpers/url.jsh.coffee +36 -0
  24. data/app/assets/javascripts/manatee/helpers/util.jsh.coffee +41 -0
  25. data/app/assets/javascripts/manatee/rails_helpers.js +2 -0
  26. data/app/assets/javascripts/manatee/rails_helpers/routes.js.erb +195 -0
  27. data/app/assets/javascripts/manatee/rails_routes.js +1 -0
  28. data/app/assets/javascripts/manatee/renderer.js.erb +53 -0
  29. data/app/assets/javascripts/manatee_railsless.js +1 -0
  30. data/lib/manatee.rb +87 -0
  31. data/lib/manatee/config.rb +51 -0
  32. data/lib/manatee/handler.rb +45 -0
  33. data/lib/manatee/rails.rb +6 -0
  34. data/lib/manatee/rails/extensions.rb +23 -0
  35. data/lib/manatee/rails/handler.rb +16 -0
  36. data/lib/manatee/rails/hash_visitor.rb +35 -0
  37. data/lib/manatee/rails/helper.rb +9 -0
  38. data/lib/manatee/rails/resolver.rb +70 -0
  39. data/lib/manatee/rails/routes_compiler.rb +34 -0
  40. data/lib/manatee/sprockets.rb +8 -0
  41. data/lib/manatee/sprockets/jsh_processor_2x.rb +32 -0
  42. data/lib/manatee/sprockets/jsh_processor_3x.rb +31 -0
  43. data/lib/manatee/version.rb +3 -0
  44. data/manatee.gemspec +32 -0
  45. data/test/example/renderer.js.erb +8 -0
  46. data/test/example/translations.en.yml +410 -0
  47. data/test/example/views/index.jst.eco +12 -0
  48. data/test/helpers/asset_tag_test.rb +175 -0
  49. data/test/helpers/asset_url_test.rb +349 -0
  50. data/test/helpers/form_options_test.rb +718 -0
  51. data/test/helpers/form_tag_test.rb +387 -0
  52. data/test/helpers/javascript_test.rb +39 -0
  53. data/test/helpers/number_test.rb +111 -0
  54. data/test/helpers/tag_test.rb +71 -0
  55. data/test/support/dom_assertion.rb +49 -0
  56. data/test/support/view_test.rb +91 -0
  57. data/test/test_helper.rb +17 -0
  58. metadata +213 -0
@@ -0,0 +1,53 @@
1
+ I18n.defaultLocale = <%= Manatee.default_locale.to_s.inspect %>;
2
+ I18n.locale = <%= Manatee.locale.to_s.inspect %>;
3
+
4
+ var <%= Manatee.template_namespace %> = <%= Manatee.template_namespace %> || {};
5
+ var <%= Manatee.renderer_namespace %> = {};
6
+
7
+ (function(){
8
+ function _pushStack(view_name, params){
9
+ var old_params = {};
10
+ for(key in params){
11
+ old_params[key] = this[key];
12
+ this[key] = params[key];
13
+ }
14
+ this._rendering_stack.push( [view_name, old_params] );
15
+ }
16
+
17
+ function _popStack(){
18
+ var stack = this._rendering_stack.pop();
19
+ for(key in stack[1]){
20
+ this[key] = stack[1][key];
21
+ }
22
+ }
23
+
24
+ function render(view_name, params){
25
+ params = params || {};
26
+ _pushStack.call(this, view_name, params);
27
+ var result = this._templates[view_name].call(this, this);
28
+ _popStack.call(this);
29
+ return result;
30
+ }
31
+
32
+ function helper(name, block){
33
+ this[name] = block.bind(this);
34
+ }
35
+
36
+ function alias(name, aliased_name){
37
+ this[name] = this[aliased_name];
38
+ }
39
+
40
+ function cleanStack(){
41
+ this._rendering_stack = [];
42
+ }
43
+
44
+ this.alias = alias.bind(this);
45
+ this.helper = helper.bind(this);
46
+ this._templates = <%= Manatee.template_namespace %>;
47
+ this._context = <%= Manatee.context.to_json %>;
48
+ this._rendering_stack = [];
49
+
50
+ this.helper('render', render);
51
+ this.helper('cleanStack', cleanStack);
52
+
53
+ }).call(<%= Manatee.renderer_namespace %>);
@@ -0,0 +1 @@
1
+ //= require ./manatee/helpers
data/lib/manatee.rb ADDED
@@ -0,0 +1,87 @@
1
+ lib = File.expand_path '..', __FILE__
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'json'
5
+ require 'execjs'
6
+ require 'i18n-js'
7
+ require 'sprockets'
8
+
9
+ require 'manatee/version'
10
+
11
+ require 'manatee/config'
12
+ require 'manatee/handler'
13
+ require 'manatee/sprockets'
14
+
15
+ if defined? Rails
16
+ require 'manatee/rails'
17
+ end
18
+
19
+ module Manatee
20
+ def self.default_config(name, value = nil)
21
+ define_singleton_method(name) do
22
+ variable = :"@#{name}"
23
+ if instance_variable_defined? variable
24
+ instance_variable_get variable
25
+ else
26
+ if block_given?
27
+ instance_variable_set variable, yield(self)
28
+ else
29
+ instance_variable_set variable, value
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ default_config :request_forgery_protection_token, :authenticity_token
36
+ default_config :protect_from_forgery, true
37
+
38
+ default_config :router_namespace, 'RR'
39
+ default_config :renderer_namespace, 'Renderer'
40
+ default_config :template_namespace, 'JST'
41
+
42
+ default_config :views_asset, 'views'
43
+ default_config :full_domain, 'http://localhost:3000'
44
+
45
+ default_config(:locale){ |c| I18n.locale }
46
+ default_config(:default_locale){ |c| I18n.default_locale }
47
+
48
+ default_config :force_domain, false
49
+ default_config :force_assets_domain, false
50
+
51
+ default_config :default_format, javascript: :js, stylesheet: :css
52
+
53
+ default_config :assets_domain, 'http://localhost:3000'
54
+
55
+ default_config(:fonts_domain){ |c| c.assets_domain }
56
+ default_config(:audios_domain){ |c| c.assets_domain }
57
+ default_config(:videos_domain){ |c| c.assets_domain }
58
+ default_config(:images_domain){ |c| c.assets_domain }
59
+ default_config(:javascript_domain){ |c| c.assets_domain }
60
+ default_config(:stylesheet_domain){ |c| c.assets_domain }
61
+
62
+ default_config :assets_path, '/assets'
63
+
64
+ default_config(:fonts_path){ |c| c.assets_path + '/fonts' }
65
+ default_config(:audios_path){ |c| c.assets_path + '/audios' }
66
+ default_config(:videos_path){ |c| c.assets_path + '/videos' }
67
+ default_config(:images_path){ |c| c.assets_path + '/images' }
68
+ default_config(:javascript_path){ |c| c.assets_path + '/javascripts' }
69
+ default_config(:stylesheet_path){ |c| c.assets_path + '/stylesheets' }
70
+
71
+ def self.assets
72
+ if defined? Rails
73
+ ::Rails.application.assets
74
+ else
75
+ @assets or raise("Manatee's Sprockets environment is not configured, call: Manatee.config{ |c| c.assets = sprockets_environment }")
76
+ end
77
+ end
78
+
79
+ def self.config(&block)
80
+ yield Manatee::Config.new
81
+ end
82
+
83
+ def self.context
84
+ Manatee::Config.context
85
+ end
86
+
87
+ end
@@ -0,0 +1,51 @@
1
+ module Manatee
2
+ class Config
3
+ def self.context
4
+ domain = {
5
+ app: Manatee.full_domain,
6
+ asset: Manatee.assets_domain,
7
+ font: Manatee.fonts_domain,
8
+ audio: Manatee.audios_domain,
9
+ video: Manatee.videos_domain,
10
+ image: Manatee.images_domain,
11
+ javascript: Manatee.javascript_domain,
12
+ stylesheet: Manatee.stylesheet_domain
13
+ }
14
+
15
+ default_path = {
16
+ asset: Manatee.assets_path,
17
+ font: Manatee.fonts_path,
18
+ audio: Manatee.audios_path,
19
+ video: Manatee.videos_path,
20
+ image: Manatee.images_path,
21
+ javascript: Manatee.javascript_path,
22
+ stylesheet: Manatee.stylesheet_path
23
+ }
24
+
25
+ force_asset_domain = Manatee.force_assets_domain || Manatee.full_domain != Manatee.assets_domain
26
+
27
+ {
28
+ domain: domain,
29
+ forceDomain: Manatee.force_domain,
30
+ defaultPath: default_path,
31
+ defaultFormat: Manatee.default_format,
32
+ forceAssetDomain: force_asset_domain,
33
+ protectFromForgery: Manatee.protect_from_forgery,
34
+ requestForgeryProtectionToken: Manatee.request_forgery_protection_token
35
+ }
36
+ end
37
+
38
+ def method_missing(method, *args, &block)
39
+ str_method = method.to_s
40
+ if str_method[-1] == '=' && Manatee.methods(false).include?(str_method[0..-2].to_sym)
41
+ if block_given?
42
+ Manatee.default_config str_method[0..-2].to_sym, &block
43
+ else
44
+ Manatee.instance_variable_set :"@#{str_method[0..-2]}", args.first
45
+ end
46
+ else
47
+ super method, *args, &block
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,45 @@
1
+ require 'singleton'
2
+
3
+ module Manatee
4
+ class Handler
5
+ include Singleton
6
+
7
+ def eval_template(identifier, params = {})
8
+ context.call javascript_template_code(identifier, params), params
9
+ end
10
+
11
+ def eval(javascript_code)
12
+ context.eval javascript_code
13
+ end
14
+
15
+ def context
16
+ check_context
17
+ @context
18
+ end
19
+
20
+ def reset!
21
+ @context = nil
22
+ end
23
+
24
+ protected
25
+ def javascript_template_code(identifier, params)
26
+ token = params[:csrf_token] ? params[:csrf_token].inspect : false
27
+ "(function(){ this.csrfToken = #{token}; return #{Manatee.template_namespace}[#{ identifier.inspect }]; }).call(#{Manatee.renderer_namespace})"
28
+ end
29
+
30
+ def check_context
31
+ load_context if !instance_variable_get(:@context) || @last_mtime != views_asset.mtime
32
+ end
33
+
34
+ def load_context
35
+ asset = views_asset
36
+ @last_mtime = asset.mtime
37
+ @context = ExecJS.compile asset.source
38
+ end
39
+
40
+ def views_asset
41
+ Manatee.assets[ Manatee.views_asset ]
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,6 @@
1
+ require 'manatee/rails/helper'
2
+ require 'manatee/rails/handler'
3
+ require 'manatee/rails/resolver'
4
+ require 'manatee/rails/extensions'
5
+ require 'manatee/rails/hash_visitor'
6
+ require 'manatee/rails/routes_compiler'
@@ -0,0 +1,23 @@
1
+ module ActionDispatch::Journey
2
+ module Nodes
3
+ class Node
4
+ def compile_hash
5
+ Manatee::Rails::HashVisitor.new.accept self
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ # This is required to Rails for using app directory
12
+ module Manatee
13
+ class Engine < ::Rails::Engine
14
+ end
15
+
16
+ # This method must be used to hook Manatee into Rails
17
+ def self.subscribe_on_rails
18
+ ActionView::Base.send :include, Manatee::Rails::Helper
19
+ ApplicationController.prepend_view_path Manatee::Rails::Resolver.new(Manatee.views_asset)
20
+ ActionView::Template.register_template_handler :'jst', Manatee::Rails::Handler.instance
21
+ Manatee::Sprockets::JshProcessor.subscribe ::Rails.application.assets
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ module Manatee
2
+ module Rails
3
+ class Handler < Manatee::Handler
4
+
5
+ def self.default_format
6
+ Mime::HTML
7
+ end
8
+
9
+ def call(template)
10
+ identifier = template.identifier
11
+ "Manatee::Handler.instance.eval_template #{ identifier.inspect }, self.assigns.except('marked_for_same_origin_verification').merge(csrf_token: form_authenticity_token)"
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ module Manatee
2
+ module Rails
3
+ class HashVisitor < ActionDispatch::Journey::Visitors::Visitor
4
+
5
+ private
6
+ def visit_GROUP(node)
7
+ {
8
+ type: node.type,
9
+ children: [ visit(node.left) ]
10
+ }
11
+ end
12
+
13
+ def terminal(node)
14
+ {
15
+ type: node.type,
16
+ value: node.left.to_s
17
+ }
18
+ end
19
+
20
+ def binary(node)
21
+ {
22
+ type: node.type,
23
+ children:[ visit(node.left), visit(node.right) ]
24
+ }
25
+ end
26
+
27
+ def nary(node)
28
+ {
29
+ type: node.type,
30
+ children: node.children.map{ |c| visit c }
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ module Manatee
2
+ module Rails
3
+ module Helper
4
+ def csrf_meta_tags
5
+ (super + content_tag(:script, "Renderer.csrfToken = #{form_authenticity_token.inspect};".html_safe))
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,70 @@
1
+ module Manatee
2
+ module Rails
3
+ class Resolver < ActionView::Resolver
4
+
5
+ def initialize(jst_template_path)
6
+ super()
7
+ @jst_template_path = jst_template_path
8
+ end
9
+
10
+ protected
11
+ def find_templates(name, prefix, partial, details)
12
+ if details[:handlers].include? :jst
13
+ path = normalize_path prefix, name, partial
14
+ locales = normalize_array details[:locale]
15
+ formats = normalize_array details[:formats]
16
+
17
+ templates = []
18
+ formats.each do |format|
19
+ locales.each do |locale|
20
+ template = find_asset_template path, locale, format
21
+ templates << template if template
22
+ end
23
+ end
24
+
25
+ templates
26
+ else
27
+ []
28
+ end
29
+ end
30
+
31
+ def find_asset_template(path, locale, format)
32
+ identifier = [normalize_identifier(path), locale, format].compact.join '.'
33
+ build_template Manatee.assets["#{identifier}.jst"], path, identifier, format
34
+ end
35
+
36
+ def normalize_path(prefix, name, partial)
37
+ name = partial ? "_#{name}" : name
38
+ prefix.present? ? "#{prefix}/#{name}" : name
39
+ end
40
+
41
+ def normalize_identifier(path)
42
+ "#{@jst_template_path}/#{path}"
43
+ end
44
+
45
+ def normalize_array(array)
46
+ return [nil] if array.blank?
47
+ normalized_array = array.map(&:to_s).uniq.compact
48
+ normalized_array << nil
49
+ end
50
+
51
+ def build_template(asset, path, identifier, format)
52
+ return nil unless asset
53
+
54
+ source = asset.source
55
+ identifier = identifier
56
+ handler = ActionView::Template.registered_template_handler :jst
57
+
58
+ format = format ? Mime[format] : Mime::HTML
59
+ details = {
60
+ format: format,
61
+ updated_at: asset.mtime,
62
+ virtual_path: path
63
+ }
64
+
65
+ ActionView::Template.new source, identifier, handler, details
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,34 @@
1
+ module Manatee
2
+ module Rails
3
+ class RoutesCompiler
4
+ def compile
5
+ named_routes.map do |name|
6
+ compile_route name, named_routes[name].path
7
+ end
8
+ end
9
+
10
+ protected
11
+ def compile_route(name, path)
12
+ {
13
+ name: name.to_s,
14
+ helper_name: helper_name(name),
15
+ names: path.names,
16
+ optional_names: path.optional_names,
17
+ required_names: path.required_names,
18
+ ast: path.spec.compile_hash
19
+ }
20
+ end
21
+
22
+ def helper_name(name)
23
+ helper_name = name.to_s.camelize
24
+ helper_name[0] = helper_name[0].downcase
25
+ helper_name
26
+ end
27
+
28
+ def named_routes
29
+ ::Rails.application.routes.named_routes
30
+ end
31
+
32
+ end
33
+ end
34
+ end