asset-packager 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +66 -0
- data/lib/asset_packager/asset_packager.rb +159 -0
- data/lib/asset_packager/jsmin.rb +205 -0
- data/lib/asset_packager/tasks.rb +25 -0
- data/lib/asset_packager/view_helper.rb +5 -0
- data/lib/asset_packager.rb +8 -0
- data/readme.md +4 -0
- data/spec/spec.opts +4 -0
- metadata +87 -0
data/Rakefile
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
Dir.chdir File.dirname(__FILE__)
|
5
|
+
|
6
|
+
# Specs
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
10
|
+
t.spec_files = FileList["spec/**/*_spec.rb"].select{|f| f !~ /\/_/}
|
11
|
+
t.libs = ['lib'].collect{|f| "#{File.dirname __FILE__}/#{f}"}
|
12
|
+
end
|
13
|
+
|
14
|
+
# Gem
|
15
|
+
require 'rake/clean'
|
16
|
+
require 'rake/gempackagetask'
|
17
|
+
require 'fileutils'
|
18
|
+
|
19
|
+
spec = Gem::Specification.new do |s|
|
20
|
+
s.name = "asset-packager"
|
21
|
+
s.version = "0.0.1"
|
22
|
+
s.summary = "Asset Packager for the Crystal framework"
|
23
|
+
s.description = "Asset Packager for the Crystal framework"
|
24
|
+
s.author = "Alexey Petrushin"
|
25
|
+
# s.email = ""
|
26
|
+
s.homepage = "http://github.com/alexeypetrushin/asset-packager"
|
27
|
+
|
28
|
+
s.platform = Gem::Platform::RUBY
|
29
|
+
s.has_rdoc = true
|
30
|
+
# s.extra_rdoc_files = ["README.rdoc"]
|
31
|
+
|
32
|
+
# s.files = (%w{rakefile readme.md .gitignore} + Dir.glob("{app,lib,spec,.git}/**/*"))
|
33
|
+
s.files = (['Rakefile', 'readme.md'] + Dir.glob("{lib,spec}/**/*"))
|
34
|
+
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
|
37
|
+
[
|
38
|
+
'crystal',
|
39
|
+
].each{|name| s.add_dependency(name)}
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
PACKAGE_DIR = "#{File.expand_path File.dirname(__FILE__)}/build"
|
44
|
+
|
45
|
+
Rake::GemPackageTask.new(spec) do |p|
|
46
|
+
package_dir = PACKAGE_DIR
|
47
|
+
# FileUtils.mkdir package_dir unless File.exist? package_dir
|
48
|
+
p.need_tar = true if RUBY_PLATFORM !~ /mswin/
|
49
|
+
p.need_zip = true
|
50
|
+
p.package_dir = package_dir
|
51
|
+
end
|
52
|
+
|
53
|
+
# CLEAN.include [ 'pkg', '*.gem']
|
54
|
+
|
55
|
+
task :push do
|
56
|
+
dir = Dir.chdir PACKAGE_DIR do
|
57
|
+
gem_file = Dir.glob("asset-packager*.gem").first
|
58
|
+
system "gem push #{gem_file}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
task :clean do
|
63
|
+
system "rm -r #{PACKAGE_DIR}"
|
64
|
+
end
|
65
|
+
|
66
|
+
task :release => [:gem, :push, :clean]
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module AssetPackager
|
2
|
+
class << self
|
3
|
+
inject :config => :config
|
4
|
+
|
5
|
+
def merged_javascripts *package_names
|
6
|
+
merged_packages 'javascripts', package_names
|
7
|
+
end
|
8
|
+
|
9
|
+
def merged_stylesheets *package_names
|
10
|
+
merged_packages 'stylesheets', package_names
|
11
|
+
end
|
12
|
+
|
13
|
+
def add yaml_file_path, asset_path
|
14
|
+
definition = YAML.load File.read(yaml_file_path)
|
15
|
+
definition.must_be.a Hash
|
16
|
+
self.definitions[asset_path] = definition
|
17
|
+
end
|
18
|
+
|
19
|
+
def build_all
|
20
|
+
definitions.each do |path, package_types|
|
21
|
+
package_types.each do |type, package|
|
22
|
+
package.each do |name, files|
|
23
|
+
build = self.send "build_#{type}", path, name, files
|
24
|
+
dir = "#{public_root}/#{type}"
|
25
|
+
FileUtils.mkdir_p dir unless File.exist? dir
|
26
|
+
fname = public_root + filename_for_builded_package(type, name)
|
27
|
+
File.open(fname, "w"){|f| f.write(build)}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete_all
|
34
|
+
definitions.each do |path, package_types|
|
35
|
+
package_types.each do |type, package|
|
36
|
+
package.each do |name, files|
|
37
|
+
fname = public_root + filename_for_builded_package(type, name)
|
38
|
+
File.delete fname if File.exist? fname
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def filename_for_builded_package type, package
|
45
|
+
type = type.to_s
|
46
|
+
"/#{type}/#{package}_packaged.#{AssetPackager.resources_extensions[type]}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def definitions
|
50
|
+
@definitions ||= {}
|
51
|
+
end
|
52
|
+
|
53
|
+
def merge_environments
|
54
|
+
@merge_environments ||= ["production"]
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
def public_root
|
59
|
+
"#{config.root}/public"
|
60
|
+
end
|
61
|
+
|
62
|
+
def tmp_path
|
63
|
+
"#{config.root}/tmp"
|
64
|
+
end
|
65
|
+
|
66
|
+
def resources_extensions
|
67
|
+
@resources_extensions ||= {
|
68
|
+
'javascripts' => 'js',
|
69
|
+
'stylesheets' => 'css'
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def build_javascripts path_to_files, package, files
|
74
|
+
merged = merge_file path_to_files, files
|
75
|
+
|
76
|
+
# write out to a temp file
|
77
|
+
tmp_file = "#{tmp_path}/#{package}_packaged"
|
78
|
+
File.open("#{tmp_file}_uncompressed.js", "w"){|f| f.write(merged)}
|
79
|
+
|
80
|
+
# compress file with JSMin library
|
81
|
+
jsmin = "#{File.dirname(__FILE__)}/jsmin.rb"
|
82
|
+
`ruby #{jsmin} <#{tmp_file}_uncompressed.js >#{tmp_file}_compressed.js \n`
|
83
|
+
|
84
|
+
# read it back in and trim it
|
85
|
+
result = ""
|
86
|
+
File.open("#{tmp_file}_compressed.js", "r") { |f| result += f.read.strip }
|
87
|
+
|
88
|
+
# delete temp files if they exist
|
89
|
+
File.delete("#{tmp_file}_uncompressed.js") if File.exists?("#{tmp_file}_uncompressed.js")
|
90
|
+
File.delete("#{tmp_file}_compressed.js") if File.exists?("#{tmp_file}_compressed.js")
|
91
|
+
|
92
|
+
result
|
93
|
+
end
|
94
|
+
|
95
|
+
def build_stylesheets path_to_files, package, files
|
96
|
+
merged = merge_file path_to_files, files
|
97
|
+
|
98
|
+
merged.gsub!(/\s+/, " ") # collapse space
|
99
|
+
merged.gsub!(/\/\*(.*?)\*\//, "") # remove comments - caution, might want to remove this if using css hacks
|
100
|
+
merged.gsub!(/\} /, "}\n") # add line breaks
|
101
|
+
merged.gsub!(/\n$/, "") # remove last break
|
102
|
+
merged.gsub!(/ \{ /, " {") # trim inside brackets
|
103
|
+
merged.gsub!(/; \}/, "}") # trim inside brackets
|
104
|
+
merged
|
105
|
+
end
|
106
|
+
|
107
|
+
def merge_file path_to_files, files
|
108
|
+
merged_file = ""
|
109
|
+
files.each do |fname|
|
110
|
+
full_path = if fname =~ /\A\//
|
111
|
+
"#{public_root}#{fname}"
|
112
|
+
else
|
113
|
+
"#{path_to_files}/#{fname}"
|
114
|
+
end
|
115
|
+
File.open(full_path, "r") do |f|
|
116
|
+
merged_file += f.read + "\n"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
merged_file
|
120
|
+
end
|
121
|
+
|
122
|
+
# TODO3 cache it
|
123
|
+
def merged_packages thetype, package_names
|
124
|
+
found_packages = {}
|
125
|
+
|
126
|
+
package_names.each do |pname|
|
127
|
+
AssetPackager.definitions.each do |path, package_types|
|
128
|
+
package_types.each do |type, packages|
|
129
|
+
next unless type == thetype
|
130
|
+
packages.each do |name, files|
|
131
|
+
found_packages[name] = files if name == pname.to_s
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
package_names.each{|name| found_packages.must.include name.to_s}
|
138
|
+
|
139
|
+
if AssetPackager.merge_environments.include? config.environment
|
140
|
+
found_packages.collect do |name, files|
|
141
|
+
AssetPackager.filename_for_builded_package thetype, name
|
142
|
+
end
|
143
|
+
else
|
144
|
+
list = []
|
145
|
+
found_packages.each do |name, files|
|
146
|
+
files.each do |fname|
|
147
|
+
fname = if fname =~ /\A\//
|
148
|
+
fname
|
149
|
+
else
|
150
|
+
"/#{fname}"
|
151
|
+
end
|
152
|
+
list.push fname
|
153
|
+
end
|
154
|
+
end
|
155
|
+
list
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# jsmin.rb 2007-07-20
|
3
|
+
# Author: Uladzislau Latynski
|
4
|
+
# This work is a translation from C to Ruby of jsmin.c published by
|
5
|
+
# Douglas Crockford. Permission is hereby granted to use the Ruby
|
6
|
+
# version under the same conditions as the jsmin.c on which it is
|
7
|
+
# based.
|
8
|
+
#
|
9
|
+
# /* jsmin.c
|
10
|
+
# 2003-04-21
|
11
|
+
#
|
12
|
+
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
13
|
+
#
|
14
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
15
|
+
# this software and associated documentation files (the "Software"), to deal in
|
16
|
+
# the Software without restriction, including without limitation the rights to
|
17
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
18
|
+
# of the Software, and to permit persons to whom the Software is furnished to do
|
19
|
+
# so, subject to the following conditions:
|
20
|
+
#
|
21
|
+
# The above copyright notice and this permission notice shall be included in all
|
22
|
+
# copies or substantial portions of the Software.
|
23
|
+
#
|
24
|
+
# The Software shall be used for Good, not Evil.
|
25
|
+
#
|
26
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
27
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
28
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
29
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
30
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
31
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
32
|
+
# SOFTWARE.
|
33
|
+
|
34
|
+
EOF = -1
|
35
|
+
$theA = ""
|
36
|
+
$theB = ""
|
37
|
+
|
38
|
+
# isAlphanum -- return true if the character is a letter, digit, underscore,
|
39
|
+
# dollar sign, or non-ASCII character
|
40
|
+
def isAlphanum(c)
|
41
|
+
return false if !c || c == EOF
|
42
|
+
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
|
43
|
+
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' ||
|
44
|
+
c == '\\' || c[0] > 126)
|
45
|
+
end
|
46
|
+
|
47
|
+
# get -- return the next character from stdin. Watch out for lookahead. If
|
48
|
+
# the character is a control character, translate it to a space or linefeed.
|
49
|
+
def get()
|
50
|
+
c = $stdin.getc
|
51
|
+
return EOF if(!c)
|
52
|
+
c = c.chr
|
53
|
+
return c if (c >= " " || c == "\n" || c.unpack("c") == EOF)
|
54
|
+
return "\n" if (c == "\r")
|
55
|
+
return " "
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get the next character without getting it.
|
59
|
+
def peek()
|
60
|
+
lookaheadChar = $stdin.getc
|
61
|
+
$stdin.ungetc(lookaheadChar)
|
62
|
+
return lookaheadChar.chr
|
63
|
+
end
|
64
|
+
|
65
|
+
# mynext -- get the next character, excluding comments.
|
66
|
+
# peek() is used to see if a '/' is followed by a '/' or '*'.
|
67
|
+
def mynext()
|
68
|
+
c = get
|
69
|
+
if (c == "/")
|
70
|
+
if(peek == "/")
|
71
|
+
while(true)
|
72
|
+
c = get
|
73
|
+
if (c <= "\n")
|
74
|
+
return c
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
if(peek == "*")
|
79
|
+
get
|
80
|
+
while(true)
|
81
|
+
case get
|
82
|
+
when "*"
|
83
|
+
if (peek == "/")
|
84
|
+
get
|
85
|
+
return " "
|
86
|
+
end
|
87
|
+
when EOF
|
88
|
+
raise "Unterminated comment"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
return c
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# action -- do something! What you do is determined by the argument: 1
|
98
|
+
# Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
|
99
|
+
# (Delete A). 3 Get the next B. (Delete B). action treats a string as a
|
100
|
+
# single character. Wow! action recognizes a regular expression if it is
|
101
|
+
# preceded by ( or , or =.
|
102
|
+
def action(a)
|
103
|
+
if(a==1)
|
104
|
+
$stdout.write $theA
|
105
|
+
end
|
106
|
+
if(a==1 || a==2)
|
107
|
+
$theA = $theB
|
108
|
+
if ($theA == "\'" || $theA == "\"")
|
109
|
+
while (true)
|
110
|
+
$stdout.write $theA
|
111
|
+
$theA = get
|
112
|
+
break if ($theA == $theB)
|
113
|
+
raise "Unterminated string literal" if ($theA <= "\n")
|
114
|
+
if ($theA == "\\")
|
115
|
+
$stdout.write $theA
|
116
|
+
$theA = get
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
if(a==1 || a==2 || a==3)
|
122
|
+
$theB = mynext
|
123
|
+
if ($theB == "/" && ($theA == "(" || $theA == "," || $theA == "=" ||
|
124
|
+
$theA == ":" || $theA == "[" || $theA == "!" ||
|
125
|
+
$theA == "&" || $theA == "|" || $theA == "?" ||
|
126
|
+
$theA == "{" || $theA == "}" || $theA == ";" ||
|
127
|
+
$theA == "\n"))
|
128
|
+
$stdout.write $theA
|
129
|
+
$stdout.write $theB
|
130
|
+
while (true)
|
131
|
+
$theA = get
|
132
|
+
if ($theA == "/")
|
133
|
+
break
|
134
|
+
elsif ($theA == "\\")
|
135
|
+
$stdout.write $theA
|
136
|
+
$theA = get
|
137
|
+
elsif ($theA <= "\n")
|
138
|
+
raise "Unterminated RegExp Literal"
|
139
|
+
end
|
140
|
+
$stdout.write $theA
|
141
|
+
end
|
142
|
+
$theB = mynext
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# jsmin -- Copy the input to the output, deleting the characters which are
|
148
|
+
# insignificant to JavaScript. Comments will be removed. Tabs will be
|
149
|
+
# replaced with spaces. Carriage returns will be replaced with linefeeds.
|
150
|
+
# Most spaces and linefeeds will be removed.
|
151
|
+
def jsmin
|
152
|
+
$theA = "\n"
|
153
|
+
action(3)
|
154
|
+
while ($theA != EOF)
|
155
|
+
case $theA
|
156
|
+
when " "
|
157
|
+
if (isAlphanum($theB))
|
158
|
+
action(1)
|
159
|
+
else
|
160
|
+
action(2)
|
161
|
+
end
|
162
|
+
when "\n"
|
163
|
+
case ($theB)
|
164
|
+
when "{","[","(","+","-"
|
165
|
+
action(1)
|
166
|
+
when " "
|
167
|
+
action(3)
|
168
|
+
else
|
169
|
+
if (isAlphanum($theB))
|
170
|
+
action(1)
|
171
|
+
else
|
172
|
+
action(2)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
else
|
176
|
+
case ($theB)
|
177
|
+
when " "
|
178
|
+
if (isAlphanum($theA))
|
179
|
+
action(1)
|
180
|
+
else
|
181
|
+
action(3)
|
182
|
+
end
|
183
|
+
when "\n"
|
184
|
+
case ($theA)
|
185
|
+
when "}","]",")","+","-","\"","\\", "'", '"'
|
186
|
+
action(1)
|
187
|
+
else
|
188
|
+
if (isAlphanum($theA))
|
189
|
+
action(1)
|
190
|
+
else
|
191
|
+
action(3)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
else
|
195
|
+
action(1)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
ARGV.each do |anArg|
|
202
|
+
$stdout.write "// #{anArg}\n"
|
203
|
+
end
|
204
|
+
|
205
|
+
jsmin
|
@@ -0,0 +1,25 @@
|
|
1
|
+
namespace :asset do
|
2
|
+
namespace :packager do
|
3
|
+
|
4
|
+
desc "Merge and compress assets"
|
5
|
+
task :build_all => :environment do
|
6
|
+
require 'yaml'
|
7
|
+
require 'asset_packager/asset_packager'
|
8
|
+
|
9
|
+
AssetPackager.build_all
|
10
|
+
|
11
|
+
puts "Asset builded"
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Delete all asset builds"
|
15
|
+
task :delete_all do
|
16
|
+
require 'yaml'
|
17
|
+
require 'asset_packager/asset_packager'
|
18
|
+
|
19
|
+
AssetPackager.delete_all
|
20
|
+
|
21
|
+
puts "Asset Builds deleted"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
raise "Asset packager must be used with Crystal::AbstractController!" unless defined? Crystal::AbstractController
|
2
|
+
|
3
|
+
require 'asset_packager/asset_packager'
|
4
|
+
require 'asset_packager/view_helper'
|
5
|
+
|
6
|
+
Crystal::ControllerContext.include AssetPackager::ViewHelper
|
7
|
+
|
8
|
+
# Use asset_packager/tasks for Rake tasks
|
data/readme.md
ADDED
data/spec/spec.opts
ADDED
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: asset-packager
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Alexey Petrushin
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-11 00:00:00 +04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: crystal
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: Asset Packager for the Crystal framework
|
36
|
+
email:
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- Rakefile
|
45
|
+
- readme.md
|
46
|
+
- lib/asset_packager/asset_packager.rb
|
47
|
+
- lib/asset_packager/jsmin.rb
|
48
|
+
- lib/asset_packager/tasks.rb
|
49
|
+
- lib/asset_packager/view_helper.rb
|
50
|
+
- lib/asset_packager.rb
|
51
|
+
- spec/spec.opts
|
52
|
+
has_rdoc: true
|
53
|
+
homepage: http://github.com/alexeypetrushin/asset-packager
|
54
|
+
licenses: []
|
55
|
+
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
hash: 3
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.3.7
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: Asset Packager for the Crystal framework
|
86
|
+
test_files: []
|
87
|
+
|