joosy-rails 1.0.0.RC1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +62 -0
- data/Rakefile +1 -0
- data/app/assets/javascripts/joosy/railties.coffee.erb +7 -0
- data/app/assets/javascripts/joosy/resource_loader.coffee +35 -0
- data/joosy-rails.gemspec +29 -0
- data/lib/joosy/rails/controller.rb +13 -0
- data/lib/joosy/rails/engine.rb +14 -0
- data/lib/joosy/rails/routing.rb +41 -0
- data/lib/joosy/rails/version.rb +5 -0
- data/lib/joosy/rails.rb +9 -0
- data/lib/rails/generators/joosy/application_generator.rb +46 -0
- data/lib/rails/generators/joosy/base.rb +61 -0
- data/lib/rails/generators/joosy/controller_generator.rb +18 -0
- data/lib/rails/generators/joosy/layout_generator.rb +9 -0
- data/lib/rails/generators/joosy/page_generator.rb +9 -0
- data/lib/rails/generators/joosy/templates/controller.rb +2 -0
- data/lib/rails/generators/joosy/templates/layout.html.erb +19 -0
- data/lib/rails/generators/joosy/widget_generator.rb +9 -0
- data/vendor/ejs.js +581 -0
- metadata +164 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f842e383f19d59b9662049c1965f5a2ee017dfd8
|
4
|
+
data.tar.gz: d5de3abe46de6cca0a897efa31f719ff58f17399
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 936a23da4bdcce1a2d8b663f94201f00913edc3f8255a13d0850c55d97b8f9f06213ca7b6ce649505564d961b7a98fc5d16aabb1af2050e41a1bdd04778cbd19
|
7
|
+
data.tar.gz: 120fe3d4024f5a5bc5e40c41b7812c6b1f52380eb60f4b115602fc027bcb3e35c43366970211a86557174e1d9e0b6c4dd91ad2c961b7cbab2a3422e6d8b524eb
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Boris Staal
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Joosy::Rails
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
Rails ties for the [Joosy](http://joosy.ws) Framework
|
6
|
+
|
7
|
+
[](http://badge.fury.io/rb/joosy-rails)
|
8
|
+
[](https://gemnasium.com/joosy/rails)
|
9
|
+
|
10
|
+
On the menu:
|
11
|
+
|
12
|
+
* Full assets integration
|
13
|
+
* Generators
|
14
|
+
* Built-in serving controller
|
15
|
+
* Routes helpers
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
gem 'joosy-rails'
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
### Generators
|
30
|
+
|
31
|
+
* `rails g joosy:application :name` – generates basic application and patches routes to make it loadable straight away.<br>
|
32
|
+
**:name** can (and in most cases should) be ommited.<br>
|
33
|
+
|
34
|
+
* `rails g joosy:layout :name (:application)` – generates new `Joosy.Layout`.<br>
|
35
|
+
**:name** can include any namespace (i.e. 'deeply/nested/layout').<br>
|
36
|
+
**:application** is a name of an application.<br>
|
37
|
+
|
38
|
+
* `rails g joosy:page :name (:application)` – generates new `Joosy.Page`.<br>
|
39
|
+
**:name** can include any namespace (i.e. 'deeply/nested/page').<br>
|
40
|
+
**:application** is a name of an application.<br>
|
41
|
+
|
42
|
+
* `rails g joosy:widget :name (:application)` – generates new `Joosy.Widget`.<br>
|
43
|
+
**:name** can include any namespace (i.e. 'deeply/nested/widget').<br>
|
44
|
+
**:application** is a name of an application.
|
45
|
+
|
46
|
+
### Serving controller and helpers
|
47
|
+
|
48
|
+
This gem provides `joosy` routing helper which can be used in the following way:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
joosy '/', application: 'dummy'
|
52
|
+
```
|
53
|
+
|
54
|
+
This will map your `dummy` Joosy application to the root url. Note that `application` option is optional and can be ommited just like `:name` option of the application generator.
|
55
|
+
|
56
|
+
## Contributing
|
57
|
+
|
58
|
+
1. Fork it
|
59
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
60
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
61
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
62
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
Joosy.ResourceLoader =
|
2
|
+
defineResource: (name, path, parent) ->
|
3
|
+
class @[name] extends parent
|
4
|
+
@entity name.underscore()
|
5
|
+
@source path
|
6
|
+
|
7
|
+
namespaceFromLevels: (levels) ->
|
8
|
+
levels.map((x) ->
|
9
|
+
res = x.replace(/^\//, '').split('/')
|
10
|
+
if res.length > 1
|
11
|
+
# resource, has second (mask) part
|
12
|
+
res = res[0].singularize()
|
13
|
+
else
|
14
|
+
# scope
|
15
|
+
res = res[0]
|
16
|
+
res.camelize()
|
17
|
+
).join('.')
|
18
|
+
|
19
|
+
loadResources: (routes) ->
|
20
|
+
for route in routes
|
21
|
+
levels = route.match /\/[^\/]+(\/:[^\/]+)?/g
|
22
|
+
continue unless Object.isArray(levels)
|
23
|
+
rootPath = levels.pop()
|
24
|
+
name = rootPath.replace(/^\//, '').singularize().camelize()
|
25
|
+
|
26
|
+
parent = if window[name] && Joosy.Module.hasAncestor(window[name], Joosy.Resources.REST)
|
27
|
+
window[name]
|
28
|
+
else if !window[name]
|
29
|
+
@defineResource.call window, name, rootPath, Joosy.Resources.REST
|
30
|
+
else
|
31
|
+
Joosy.Resources.REST
|
32
|
+
|
33
|
+
if (ns = @namespaceFromLevels(levels)) != ''
|
34
|
+
Joosy.namespace ns, ->
|
35
|
+
Joosy.ResourceLoader.defineResource.call @, name, route, parent
|
data/joosy-rails.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'joosy/rails/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'joosy-rails'
|
8
|
+
spec.version = Joosy::Rails::VERSION
|
9
|
+
spec.authors = ['Boris Staal']
|
10
|
+
spec.email = ['boris@staal.io']
|
11
|
+
spec.summary = 'Joosy Rails ties'
|
12
|
+
spec.description = 'Assets, Generators and beer delivery'
|
13
|
+
spec.homepage = 'http://github.com/joosy/rails'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'joosy', '>= 1.2.0.alpha.63'
|
22
|
+
spec.add_dependency 'sprockets'
|
23
|
+
spec.add_dependency 'execjs'
|
24
|
+
spec.add_dependency 'activesupport'
|
25
|
+
spec.add_dependency 'thor'
|
26
|
+
|
27
|
+
spec.add_dependency 'sugar-rails'
|
28
|
+
spec.add_dependency 'jquery-form-rails'
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Joosy
|
2
|
+
module Rails
|
3
|
+
class ServeController < ActionController::Base
|
4
|
+
def index
|
5
|
+
@prefix = request.env['SCRIPT_NAME']
|
6
|
+
layout = 'joosy'
|
7
|
+
layout << "/#{params[:application]}" if params[:application]
|
8
|
+
|
9
|
+
render text: '', layout: layout
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/engine'
|
2
|
+
|
3
|
+
module Joosy
|
4
|
+
module Rails
|
5
|
+
class Engine < ::Rails::Engine
|
6
|
+
cattr_accessor :resources
|
7
|
+
self.resources = []
|
8
|
+
|
9
|
+
initializer 'joosy.extend.sprockets' do |app|
|
10
|
+
Joosy.assets_paths.each{|p| app.assets.append_path p}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'action_dispatch/routing/mapper'
|
2
|
+
|
3
|
+
module ActionDispatch::Routing
|
4
|
+
class Mapper
|
5
|
+
module Resources
|
6
|
+
class JoosyResource
|
7
|
+
def initialize(context)
|
8
|
+
@context = context
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(name, *args, &block)
|
12
|
+
@context.send(name, *args, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def resources(*args, &block)
|
16
|
+
@context.resources(*args) do
|
17
|
+
scope = @context.instance_eval { @scope }
|
18
|
+
Joosy::Rails::Engine.resources << "#{scope[:path]}/#{scope[:scope_level_resource].path}"
|
19
|
+
@context.joosy_resources(&block)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def joosy_resources(&block)
|
25
|
+
JoosyResource.new(self).instance_eval(&block) if block_given?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def joosy(route, options={})
|
30
|
+
extender = route.last == '/' ? '(*x)' : '(/*x)'
|
31
|
+
|
32
|
+
get route,
|
33
|
+
controller: options[:controller] || 'joosy/rails/serve',
|
34
|
+
action: options[:action] || 'index',
|
35
|
+
as: (options[:application] ? "joosy_#{options[:application]}" : "joosy"),
|
36
|
+
defaults: {route: route, application: options[:application]},
|
37
|
+
anchor: false,
|
38
|
+
format: false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/joosy/rails.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
|
3
|
+
module Joosy
|
4
|
+
module Generators
|
5
|
+
class ApplicationGenerator < Base
|
6
|
+
argument :name, type: :string, optional: true
|
7
|
+
|
8
|
+
def create_application
|
9
|
+
dependencies = <<-COFFEE
|
10
|
+
#= require jquery
|
11
|
+
#= require jquery.form
|
12
|
+
#= require sugar
|
13
|
+
#= require hamlcoffee
|
14
|
+
COFFEE
|
15
|
+
|
16
|
+
@options = {
|
17
|
+
'dependencies' => dependencies,
|
18
|
+
'html5' => true,
|
19
|
+
'prefix' => name || ''
|
20
|
+
}
|
21
|
+
|
22
|
+
directory 'application', Pathname.new('app/assets/javascripts/').join(name || '')
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_bindings
|
26
|
+
self.destination_root = ::Rails.root
|
27
|
+
|
28
|
+
if !name
|
29
|
+
index = ::Rails.root.join('app/assets/javascripts/application.js')
|
30
|
+
|
31
|
+
if File.exists?(index)
|
32
|
+
copy_file index, 'app/assets/javascripts/application.old.js'
|
33
|
+
remove_file index
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
layout = 'joosy'
|
38
|
+
layout << "/#{name}" if name
|
39
|
+
erb_template File.expand_path('../templates/layout.html.erb', __FILE__), "app/views/layouts/#{layout}.html.erb"
|
40
|
+
|
41
|
+
application = name ? ", application: '#{name}'" : ''
|
42
|
+
route "joosy '/#{name}'#{application}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'sprockets'
|
3
|
+
require 'execjs'
|
4
|
+
|
5
|
+
module Joosy
|
6
|
+
module Generators
|
7
|
+
class Base < ::Rails::Generators::Base
|
8
|
+
no_tasks do
|
9
|
+
class <<self
|
10
|
+
attr_accessor :kind
|
11
|
+
end
|
12
|
+
|
13
|
+
alias_method :erb_template, :template
|
14
|
+
|
15
|
+
def template(source, destination=nil, config={})
|
16
|
+
destination ||= source
|
17
|
+
source = File.expand_path(find_in_source_paths(source.to_s))
|
18
|
+
context = instance_eval('binding')
|
19
|
+
|
20
|
+
create_file destination, nil, config do
|
21
|
+
self.class.ejs ::File.read(source), @options
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def self.sprockets
|
29
|
+
return @sprockets if @sprockets
|
30
|
+
|
31
|
+
@sprockets = Sprockets::Environment.new
|
32
|
+
@sprockets.append_path File.expand_path('../../../../../vendor/', __FILE__)
|
33
|
+
@sprockets
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.ejs(template, data)
|
37
|
+
ExecJS.compile(sprockets['ejs'].to_s).eval("ejs.compile(#{template.to_json})(#{data.to_json})")
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.source_root
|
41
|
+
Joosy.templates_path
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Entity < Base
|
46
|
+
argument :name, type: :string
|
47
|
+
argument :application, type: :string, optional: true
|
48
|
+
|
49
|
+
def create_files
|
50
|
+
@options = {
|
51
|
+
'name' => name,
|
52
|
+
'namespace' => name.split('/')[0..-2].map(&:camelize).join('/'),
|
53
|
+
'view' => name.split('/').last,
|
54
|
+
'klass' => name.split('/').last.camelize
|
55
|
+
}
|
56
|
+
|
57
|
+
directory self.class.kind, Pathname.new('app/assets/javascripts/').join(application || '')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Joosy
|
2
|
+
module Generators
|
3
|
+
class ControllerGenerator < ::Rails::Generators::Base
|
4
|
+
argument :name, type: :string
|
5
|
+
class_option :copy, :default => false, :type => :boolean, :desc => 'Indicates whether internal controller should be copied'
|
6
|
+
|
7
|
+
source_root ::Rails.root
|
8
|
+
|
9
|
+
def create_files
|
10
|
+
if options["copy"]
|
11
|
+
template File.expand_path('../../../../joosy/rails/controller.rb', __FILE__), "app/controller/joosy/rails/serve_controller.rb"
|
12
|
+
else
|
13
|
+
template File.expand_path('../templates/controller.rb', __FILE__), "app/controllers/#{name.underscore}_controller.rb"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title></title>
|
5
|
+
<script type="text/javascript">
|
6
|
+
window.JoosyEnvironment = {
|
7
|
+
router: {
|
8
|
+
prefix: <%= '<%= raw @prefix.to_json %'+'>' %>
|
9
|
+
}
|
10
|
+
}
|
11
|
+
</script>
|
12
|
+
|
13
|
+
<%= "<%= stylesheet_link_tag 'application', :media => 'all' %"+'>' %>
|
14
|
+
<%= "<%= javascript_include_tag '#{name}#{'/' if name}application' %"+'>' %>
|
15
|
+
<%= '<%= csrf_meta_tags %'+'>' %>
|
16
|
+
</head>
|
17
|
+
<body>
|
18
|
+
</body>
|
19
|
+
</html>
|
data/vendor/ejs.js
ADDED
@@ -0,0 +1,581 @@
|
|
1
|
+
ejs = (function(){
|
2
|
+
|
3
|
+
// CommonJS require()
|
4
|
+
|
5
|
+
function require(p){
|
6
|
+
if ('fs' == p) return {};
|
7
|
+
var path = require.resolve(p)
|
8
|
+
, mod = require.modules[path];
|
9
|
+
if (!mod) throw new Error('failed to require "' + p + '"');
|
10
|
+
if (!mod.exports) {
|
11
|
+
mod.exports = {};
|
12
|
+
mod.call(mod.exports, mod, mod.exports, require.relative(path));
|
13
|
+
}
|
14
|
+
return mod.exports;
|
15
|
+
}
|
16
|
+
|
17
|
+
require.modules = {};
|
18
|
+
|
19
|
+
require.resolve = function (path){
|
20
|
+
var orig = path
|
21
|
+
, reg = path + '.js'
|
22
|
+
, index = path + '/index.js';
|
23
|
+
return require.modules[reg] && reg
|
24
|
+
|| require.modules[index] && index
|
25
|
+
|| orig;
|
26
|
+
};
|
27
|
+
|
28
|
+
require.register = function (path, fn){
|
29
|
+
require.modules[path] = fn;
|
30
|
+
};
|
31
|
+
|
32
|
+
require.relative = function (parent) {
|
33
|
+
return function(p){
|
34
|
+
if ('.' != p.substr(0, 1)) return require(p);
|
35
|
+
|
36
|
+
var path = parent.split('/')
|
37
|
+
, segs = p.split('/');
|
38
|
+
path.pop();
|
39
|
+
|
40
|
+
for (var i = 0; i < segs.length; i++) {
|
41
|
+
var seg = segs[i];
|
42
|
+
if ('..' == seg) path.pop();
|
43
|
+
else if ('.' != seg) path.push(seg);
|
44
|
+
}
|
45
|
+
|
46
|
+
return require(path.join('/'));
|
47
|
+
};
|
48
|
+
};
|
49
|
+
|
50
|
+
|
51
|
+
require.register("ejs.js", function(module, exports, require){
|
52
|
+
|
53
|
+
/*!
|
54
|
+
* EJS
|
55
|
+
* Copyright(c) 2012 TJ Holowaychuk <tj@vision-media.ca>
|
56
|
+
* MIT Licensed
|
57
|
+
*/
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Module dependencies.
|
61
|
+
*/
|
62
|
+
|
63
|
+
var utils = require('./utils')
|
64
|
+
, fs = require('fs');
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Library version.
|
68
|
+
*/
|
69
|
+
|
70
|
+
exports.version = '0.7.2';
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Filters.
|
74
|
+
*
|
75
|
+
* @type Object
|
76
|
+
*/
|
77
|
+
|
78
|
+
var filters = exports.filters = require('./filters');
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Intermediate js cache.
|
82
|
+
*
|
83
|
+
* @type Object
|
84
|
+
*/
|
85
|
+
|
86
|
+
var cache = {};
|
87
|
+
|
88
|
+
/**
|
89
|
+
* Clear intermediate js cache.
|
90
|
+
*
|
91
|
+
* @api public
|
92
|
+
*/
|
93
|
+
|
94
|
+
exports.clearCache = function(){
|
95
|
+
cache = {};
|
96
|
+
};
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Translate filtered code into function calls.
|
100
|
+
*
|
101
|
+
* @param {String} js
|
102
|
+
* @return {String}
|
103
|
+
* @api private
|
104
|
+
*/
|
105
|
+
|
106
|
+
function filtered(js) {
|
107
|
+
return js.substr(1).split('|').reduce(function(js, filter){
|
108
|
+
var parts = filter.split(':')
|
109
|
+
, name = parts.shift()
|
110
|
+
, args = parts.shift() || '';
|
111
|
+
if (args) args = ', ' + args;
|
112
|
+
return 'filters.' + name + '(' + js + args + ')';
|
113
|
+
});
|
114
|
+
};
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Re-throw the given `err` in context to the
|
118
|
+
* `str` of ejs, `filename`, and `lineno`.
|
119
|
+
*
|
120
|
+
* @param {Error} err
|
121
|
+
* @param {String} str
|
122
|
+
* @param {String} filename
|
123
|
+
* @param {String} lineno
|
124
|
+
* @api private
|
125
|
+
*/
|
126
|
+
|
127
|
+
function rethrow(err, str, filename, lineno){
|
128
|
+
var lines = str.split('\n')
|
129
|
+
, start = Math.max(lineno - 3, 0)
|
130
|
+
, end = Math.min(lines.length, lineno + 3);
|
131
|
+
|
132
|
+
// Error context
|
133
|
+
var context = lines.slice(start, end).map(function(line, i){
|
134
|
+
var curr = i + start + 1;
|
135
|
+
return (curr == lineno ? ' >> ' : ' ')
|
136
|
+
+ curr
|
137
|
+
+ '| '
|
138
|
+
+ line;
|
139
|
+
}).join('\n');
|
140
|
+
|
141
|
+
// Alter exception message
|
142
|
+
err.path = filename;
|
143
|
+
err.message = (filename || 'ejs') + ':'
|
144
|
+
+ lineno + '\n'
|
145
|
+
+ context + '\n\n'
|
146
|
+
+ err.message;
|
147
|
+
|
148
|
+
throw err;
|
149
|
+
}
|
150
|
+
|
151
|
+
/**
|
152
|
+
* Parse the given `str` of ejs, returning the function body.
|
153
|
+
*
|
154
|
+
* @param {String} str
|
155
|
+
* @return {String}
|
156
|
+
* @api public
|
157
|
+
*/
|
158
|
+
|
159
|
+
var parse = exports.parse = function(str, options){
|
160
|
+
var options = options || {}
|
161
|
+
, open = options.open || exports.open || '<%'
|
162
|
+
, close = options.close || exports.close || '%>';
|
163
|
+
|
164
|
+
var buf = [
|
165
|
+
"var buf = [];"
|
166
|
+
, "\nwith (locals) {"
|
167
|
+
, "\n buf.push('"
|
168
|
+
];
|
169
|
+
|
170
|
+
var lineno = 1;
|
171
|
+
|
172
|
+
var consumeEOL = false;
|
173
|
+
for (var i = 0, len = str.length; i < len; ++i) {
|
174
|
+
if (str.slice(i, open.length + i) == open) {
|
175
|
+
i += open.length
|
176
|
+
|
177
|
+
var prefix, postfix, line = '__stack.lineno=' + lineno;
|
178
|
+
switch (str.substr(i, 1)) {
|
179
|
+
case '=':
|
180
|
+
prefix = "', escape((" + line + ', ';
|
181
|
+
postfix = ")), '";
|
182
|
+
++i;
|
183
|
+
break;
|
184
|
+
case '-':
|
185
|
+
prefix = "', (" + line + ', ';
|
186
|
+
postfix = "), '";
|
187
|
+
++i;
|
188
|
+
break;
|
189
|
+
default:
|
190
|
+
prefix = "');" + line + ';';
|
191
|
+
postfix = "; buf.push('";
|
192
|
+
}
|
193
|
+
|
194
|
+
var end = str.indexOf(close, i)
|
195
|
+
, js = str.substring(i, end)
|
196
|
+
, start = i
|
197
|
+
, n = 0;
|
198
|
+
|
199
|
+
if ('-' == js[js.length-1]){
|
200
|
+
js = js.substring(0, js.length - 2);
|
201
|
+
consumeEOL = true;
|
202
|
+
}
|
203
|
+
|
204
|
+
while (~(n = js.indexOf("\n", n))) n++, lineno++;
|
205
|
+
if (js.substr(0, 1) == ':') js = filtered(js);
|
206
|
+
buf.push(prefix, js, postfix);
|
207
|
+
i += end - start + close.length - 1;
|
208
|
+
|
209
|
+
} else if (str.substr(i, 1) == "\\") {
|
210
|
+
buf.push("\\\\");
|
211
|
+
} else if (str.substr(i, 1) == "'") {
|
212
|
+
buf.push("\\'");
|
213
|
+
} else if (str.substr(i, 1) == "\r") {
|
214
|
+
buf.push(" ");
|
215
|
+
} else if (str.substr(i, 1) == "\n") {
|
216
|
+
if (consumeEOL) {
|
217
|
+
consumeEOL = false;
|
218
|
+
} else {
|
219
|
+
buf.push("\\n");
|
220
|
+
lineno++;
|
221
|
+
}
|
222
|
+
} else {
|
223
|
+
buf.push(str.substr(i, 1));
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
227
|
+
buf.push("');\n}\nreturn buf.join('');");
|
228
|
+
return buf.join('');
|
229
|
+
};
|
230
|
+
|
231
|
+
/**
|
232
|
+
* Compile the given `str` of ejs into a `Function`.
|
233
|
+
*
|
234
|
+
* @param {String} str
|
235
|
+
* @param {Object} options
|
236
|
+
* @return {Function}
|
237
|
+
* @api public
|
238
|
+
*/
|
239
|
+
|
240
|
+
var compile = exports.compile = function(str, options){
|
241
|
+
options = options || {};
|
242
|
+
|
243
|
+
var input = JSON.stringify(str)
|
244
|
+
, filename = options.filename
|
245
|
+
? JSON.stringify(options.filename)
|
246
|
+
: 'undefined';
|
247
|
+
|
248
|
+
// Adds the fancy stack trace meta info
|
249
|
+
str = [
|
250
|
+
'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };',
|
251
|
+
rethrow.toString(),
|
252
|
+
'try {',
|
253
|
+
exports.parse(str, options),
|
254
|
+
'} catch (err) {',
|
255
|
+
' rethrow(err, __stack.input, __stack.filename, __stack.lineno);',
|
256
|
+
'}'
|
257
|
+
].join("\n");
|
258
|
+
|
259
|
+
if (options.debug) console.log(str);
|
260
|
+
var fn = new Function('locals, filters, escape', str);
|
261
|
+
return function(locals){
|
262
|
+
return fn.call(this, locals, filters, utils.escape);
|
263
|
+
}
|
264
|
+
};
|
265
|
+
|
266
|
+
/**
|
267
|
+
* Render the given `str` of ejs.
|
268
|
+
*
|
269
|
+
* Options:
|
270
|
+
*
|
271
|
+
* - `locals` Local variables object
|
272
|
+
* - `cache` Compiled functions are cached, requires `filename`
|
273
|
+
* - `filename` Used by `cache` to key caches
|
274
|
+
* - `scope` Function execution context
|
275
|
+
* - `debug` Output generated function body
|
276
|
+
* - `open` Open tag, defaulting to "<%"
|
277
|
+
* - `close` Closing tag, defaulting to "%>"
|
278
|
+
*
|
279
|
+
* @param {String} str
|
280
|
+
* @param {Object} options
|
281
|
+
* @return {String}
|
282
|
+
* @api public
|
283
|
+
*/
|
284
|
+
|
285
|
+
exports.render = function(str, options){
|
286
|
+
var fn
|
287
|
+
, options = options || {};
|
288
|
+
|
289
|
+
if (options.cache) {
|
290
|
+
if (options.filename) {
|
291
|
+
fn = cache[options.filename] || (cache[options.filename] = compile(str, options));
|
292
|
+
} else {
|
293
|
+
throw new Error('"cache" option requires "filename".');
|
294
|
+
}
|
295
|
+
} else {
|
296
|
+
fn = compile(str, options);
|
297
|
+
}
|
298
|
+
|
299
|
+
options.__proto__ = options.locals;
|
300
|
+
return fn.call(options.scope, options);
|
301
|
+
};
|
302
|
+
|
303
|
+
/**
|
304
|
+
* Render an EJS file at the given `path` and callback `fn(err, str)`.
|
305
|
+
*
|
306
|
+
* @param {String} path
|
307
|
+
* @param {Object|Function} options or callback
|
308
|
+
* @param {Function} fn
|
309
|
+
* @api public
|
310
|
+
*/
|
311
|
+
|
312
|
+
exports.renderFile = function(path, options, fn){
|
313
|
+
var key = path + ':string';
|
314
|
+
|
315
|
+
if ('function' == typeof options) {
|
316
|
+
fn = options, options = {};
|
317
|
+
}
|
318
|
+
|
319
|
+
options.filename = path;
|
320
|
+
|
321
|
+
try {
|
322
|
+
var str = options.cache
|
323
|
+
? cache[key] || (cache[key] = fs.readFileSync(path, 'utf8'))
|
324
|
+
: fs.readFileSync(path, 'utf8');
|
325
|
+
|
326
|
+
fn(null, exports.render(str, options));
|
327
|
+
} catch (err) {
|
328
|
+
fn(err);
|
329
|
+
}
|
330
|
+
};
|
331
|
+
|
332
|
+
// express support
|
333
|
+
|
334
|
+
exports.__express = exports.renderFile;
|
335
|
+
|
336
|
+
/**
|
337
|
+
* Expose to require().
|
338
|
+
*/
|
339
|
+
|
340
|
+
if (require.extensions) {
|
341
|
+
require.extensions['.ejs'] = function(module, filename) {
|
342
|
+
source = require('fs').readFileSync(filename, 'utf-8');
|
343
|
+
module._compile(compile(source, {}), filename);
|
344
|
+
};
|
345
|
+
} else if (require.registerExtension) {
|
346
|
+
require.registerExtension('.ejs', function(src) {
|
347
|
+
return compile(src, {});
|
348
|
+
});
|
349
|
+
}
|
350
|
+
|
351
|
+
}); // module: ejs.js
|
352
|
+
|
353
|
+
require.register("filters.js", function(module, exports, require){
|
354
|
+
|
355
|
+
/*!
|
356
|
+
* EJS - Filters
|
357
|
+
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
358
|
+
* MIT Licensed
|
359
|
+
*/
|
360
|
+
|
361
|
+
/**
|
362
|
+
* First element of the target `obj`.
|
363
|
+
*/
|
364
|
+
|
365
|
+
exports.first = function(obj) {
|
366
|
+
return obj[0];
|
367
|
+
};
|
368
|
+
|
369
|
+
/**
|
370
|
+
* Last element of the target `obj`.
|
371
|
+
*/
|
372
|
+
|
373
|
+
exports.last = function(obj) {
|
374
|
+
return obj[obj.length - 1];
|
375
|
+
};
|
376
|
+
|
377
|
+
/**
|
378
|
+
* Capitalize the first letter of the target `str`.
|
379
|
+
*/
|
380
|
+
|
381
|
+
exports.capitalize = function(str){
|
382
|
+
str = String(str);
|
383
|
+
return str[0].toUpperCase() + str.substr(1, str.length);
|
384
|
+
};
|
385
|
+
|
386
|
+
/**
|
387
|
+
* Downcase the target `str`.
|
388
|
+
*/
|
389
|
+
|
390
|
+
exports.downcase = function(str){
|
391
|
+
return String(str).toLowerCase();
|
392
|
+
};
|
393
|
+
|
394
|
+
/**
|
395
|
+
* Uppercase the target `str`.
|
396
|
+
*/
|
397
|
+
|
398
|
+
exports.upcase = function(str){
|
399
|
+
return String(str).toUpperCase();
|
400
|
+
};
|
401
|
+
|
402
|
+
/**
|
403
|
+
* Sort the target `obj`.
|
404
|
+
*/
|
405
|
+
|
406
|
+
exports.sort = function(obj){
|
407
|
+
return Object.create(obj).sort();
|
408
|
+
};
|
409
|
+
|
410
|
+
/**
|
411
|
+
* Sort the target `obj` by the given `prop` ascending.
|
412
|
+
*/
|
413
|
+
|
414
|
+
exports.sort_by = function(obj, prop){
|
415
|
+
return Object.create(obj).sort(function(a, b){
|
416
|
+
a = a[prop], b = b[prop];
|
417
|
+
if (a > b) return 1;
|
418
|
+
if (a < b) return -1;
|
419
|
+
return 0;
|
420
|
+
});
|
421
|
+
};
|
422
|
+
|
423
|
+
/**
|
424
|
+
* Size or length of the target `obj`.
|
425
|
+
*/
|
426
|
+
|
427
|
+
exports.size = exports.length = function(obj) {
|
428
|
+
return obj.length;
|
429
|
+
};
|
430
|
+
|
431
|
+
/**
|
432
|
+
* Add `a` and `b`.
|
433
|
+
*/
|
434
|
+
|
435
|
+
exports.plus = function(a, b){
|
436
|
+
return Number(a) + Number(b);
|
437
|
+
};
|
438
|
+
|
439
|
+
/**
|
440
|
+
* Subtract `b` from `a`.
|
441
|
+
*/
|
442
|
+
|
443
|
+
exports.minus = function(a, b){
|
444
|
+
return Number(a) - Number(b);
|
445
|
+
};
|
446
|
+
|
447
|
+
/**
|
448
|
+
* Multiply `a` by `b`.
|
449
|
+
*/
|
450
|
+
|
451
|
+
exports.times = function(a, b){
|
452
|
+
return Number(a) * Number(b);
|
453
|
+
};
|
454
|
+
|
455
|
+
/**
|
456
|
+
* Divide `a` by `b`.
|
457
|
+
*/
|
458
|
+
|
459
|
+
exports.divided_by = function(a, b){
|
460
|
+
return Number(a) / Number(b);
|
461
|
+
};
|
462
|
+
|
463
|
+
/**
|
464
|
+
* Join `obj` with the given `str`.
|
465
|
+
*/
|
466
|
+
|
467
|
+
exports.join = function(obj, str){
|
468
|
+
return obj.join(str || ', ');
|
469
|
+
};
|
470
|
+
|
471
|
+
/**
|
472
|
+
* Truncate `str` to `len`.
|
473
|
+
*/
|
474
|
+
|
475
|
+
exports.truncate = function(str, len){
|
476
|
+
str = String(str);
|
477
|
+
return str.substr(0, len);
|
478
|
+
};
|
479
|
+
|
480
|
+
/**
|
481
|
+
* Truncate `str` to `n` words.
|
482
|
+
*/
|
483
|
+
|
484
|
+
exports.truncate_words = function(str, n){
|
485
|
+
var str = String(str)
|
486
|
+
, words = str.split(/ +/);
|
487
|
+
return words.slice(0, n).join(' ');
|
488
|
+
};
|
489
|
+
|
490
|
+
/**
|
491
|
+
* Replace `pattern` with `substitution` in `str`.
|
492
|
+
*/
|
493
|
+
|
494
|
+
exports.replace = function(str, pattern, substitution){
|
495
|
+
return String(str).replace(pattern, substitution || '');
|
496
|
+
};
|
497
|
+
|
498
|
+
/**
|
499
|
+
* Prepend `val` to `obj`.
|
500
|
+
*/
|
501
|
+
|
502
|
+
exports.prepend = function(obj, val){
|
503
|
+
return Array.isArray(obj)
|
504
|
+
? [val].concat(obj)
|
505
|
+
: val + obj;
|
506
|
+
};
|
507
|
+
|
508
|
+
/**
|
509
|
+
* Append `val` to `obj`.
|
510
|
+
*/
|
511
|
+
|
512
|
+
exports.append = function(obj, val){
|
513
|
+
return Array.isArray(obj)
|
514
|
+
? obj.concat(val)
|
515
|
+
: obj + val;
|
516
|
+
};
|
517
|
+
|
518
|
+
/**
|
519
|
+
* Map the given `prop`.
|
520
|
+
*/
|
521
|
+
|
522
|
+
exports.map = function(arr, prop){
|
523
|
+
return arr.map(function(obj){
|
524
|
+
return obj[prop];
|
525
|
+
});
|
526
|
+
};
|
527
|
+
|
528
|
+
/**
|
529
|
+
* Reverse the given `obj`.
|
530
|
+
*/
|
531
|
+
|
532
|
+
exports.reverse = function(obj){
|
533
|
+
return Array.isArray(obj)
|
534
|
+
? obj.reverse()
|
535
|
+
: String(obj).split('').reverse().join('');
|
536
|
+
};
|
537
|
+
|
538
|
+
/**
|
539
|
+
* Get `prop` of the given `obj`.
|
540
|
+
*/
|
541
|
+
|
542
|
+
exports.get = function(obj, prop){
|
543
|
+
return obj[prop];
|
544
|
+
};
|
545
|
+
|
546
|
+
/**
|
547
|
+
* Packs the given `obj` into json string
|
548
|
+
*/
|
549
|
+
exports.json = function(obj){
|
550
|
+
return JSON.stringify(obj);
|
551
|
+
};
|
552
|
+
}); // module: filters.js
|
553
|
+
|
554
|
+
require.register("utils.js", function(module, exports, require){
|
555
|
+
|
556
|
+
/*!
|
557
|
+
* EJS
|
558
|
+
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
559
|
+
* MIT Licensed
|
560
|
+
*/
|
561
|
+
|
562
|
+
/**
|
563
|
+
* Escape the given string of `html`.
|
564
|
+
*
|
565
|
+
* @param {String} html
|
566
|
+
* @return {String}
|
567
|
+
* @api private
|
568
|
+
*/
|
569
|
+
|
570
|
+
exports.escape = function(html){
|
571
|
+
return String(html)
|
572
|
+
.replace(/&(?!\w+;)/g, '&')
|
573
|
+
.replace(/</g, '<')
|
574
|
+
.replace(/>/g, '>')
|
575
|
+
.replace(/"/g, '"');
|
576
|
+
};
|
577
|
+
|
578
|
+
}); // module: utils.js
|
579
|
+
|
580
|
+
return require("ejs");
|
581
|
+
})();
|
metadata
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: joosy-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.RC1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Boris Staal
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-08-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: joosy
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.2.0.alpha.63
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.2.0.alpha.63
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sprockets
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: execjs
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: thor
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: sugar-rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: jquery-form-rails
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Assets, Generators and beer delivery
|
112
|
+
email:
|
113
|
+
- boris@staal.io
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- Gemfile
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- app/assets/javascripts/joosy/railties.coffee.erb
|
124
|
+
- app/assets/javascripts/joosy/resource_loader.coffee
|
125
|
+
- joosy-rails.gemspec
|
126
|
+
- lib/joosy/rails.rb
|
127
|
+
- lib/joosy/rails/controller.rb
|
128
|
+
- lib/joosy/rails/engine.rb
|
129
|
+
- lib/joosy/rails/routing.rb
|
130
|
+
- lib/joosy/rails/version.rb
|
131
|
+
- lib/rails/generators/joosy/application_generator.rb
|
132
|
+
- lib/rails/generators/joosy/base.rb
|
133
|
+
- lib/rails/generators/joosy/controller_generator.rb
|
134
|
+
- lib/rails/generators/joosy/layout_generator.rb
|
135
|
+
- lib/rails/generators/joosy/page_generator.rb
|
136
|
+
- lib/rails/generators/joosy/templates/controller.rb
|
137
|
+
- lib/rails/generators/joosy/templates/layout.html.erb
|
138
|
+
- lib/rails/generators/joosy/widget_generator.rb
|
139
|
+
- vendor/ejs.js
|
140
|
+
homepage: http://github.com/joosy/rails
|
141
|
+
licenses:
|
142
|
+
- MIT
|
143
|
+
metadata: {}
|
144
|
+
post_install_message:
|
145
|
+
rdoc_options: []
|
146
|
+
require_paths:
|
147
|
+
- lib
|
148
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - '>'
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 1.3.1
|
158
|
+
requirements: []
|
159
|
+
rubyforge_project:
|
160
|
+
rubygems_version: 2.0.6
|
161
|
+
signing_key:
|
162
|
+
specification_version: 4
|
163
|
+
summary: Joosy Rails ties
|
164
|
+
test_files: []
|