slinky 0.1.0

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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "eventmachine", ">= 0.12.0"
4
+ gem "eventmachine_httpserver", ">= 0.2.0"
5
+
6
+ group :development do
7
+ gem "bacon", ">= 0"
8
+ gem "yard", "~> 0.6.0"
9
+ gem "bundler", "~> 1.0.0"
10
+ gem "jeweler", "~> 1.5.2"
11
+ gem "rcov", ">= 0"
12
+ end
13
+
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 mwylde
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.
data/README.md ADDED
@@ -0,0 +1,6 @@
1
+ #Slinky
2
+
3
+ Slinky is a static file server designed to make development of static
4
+ web sites and applications simpler. Simply run slinky in the home
5
+ directory of your app and it will serve while compiling things like
6
+ SASS, HAML and CoffeeScript on the fly.
data/Rakefile ADDED
@@ -0,0 +1,42 @@
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 = "slinky"
16
+ gem.homepage = "http://github.com/mwylde/slinky"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Static file server for javascript apps}
19
+ gem.description = %Q{A static file server for rich javascript apps that automatically compiles SASS, HAML, CoffeeScript and more}
20
+ gem.email = "mwylde@wesleyan.edu"
21
+ gem.authors = ["mwylde"]
22
+ end
23
+ Jeweler::RubygemsDotOrgTasks.new
24
+
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:spec) do |spec|
27
+ spec.libs << 'lib' << 'spec'
28
+ spec.pattern = 'spec/**/*_spec.rb'
29
+ spec.verbose = true
30
+ end
31
+
32
+ require 'rcov/rcovtask'
33
+ Rcov::RcovTask.new do |spec|
34
+ spec.libs << 'spec'
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.verbose = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'yard'
42
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/slinky ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'slinky'
4
+
5
+ Slinky::Runner.run
@@ -0,0 +1,56 @@
1
+ module Slinky
2
+ # Stores information about compiled files, including location,
3
+ # source file and last modified time
4
+ class CompiledFile
5
+ attr_reader :source, :last_compiled
6
+
7
+ # Creates a new CompiledFile, compiling the provided source file
8
+ # with the provided compiler class.
9
+ def initialize source, compiler
10
+ @source = source
11
+ @compiler = compiler
12
+ @last_compiled = Time.new(0)
13
+ end
14
+
15
+ # Compiles the source file to a temporary location
16
+ def compile &cb
17
+ path = @path || tmp_path
18
+
19
+ command = @compiler.command @source, path
20
+
21
+ puts "Running command '#{command}'"
22
+
23
+ EM.system3 command do |stdout, stderr, status|
24
+ @last_compiled = Time.now
25
+ if status.exitstatus != 0
26
+ $stderr.write "Failed on #{@source}: #{stderr.strip}\n"
27
+ else
28
+ puts "Compiled #{@source}"
29
+ @path = path
30
+ end
31
+ cb.call(@path, status, stdout, stderr)
32
+ end
33
+ end
34
+
35
+ # Calls the supplied callback with the path of the compiled file,
36
+ # compiling the source file first if necessary.
37
+ def file &cb
38
+ if needs_update?
39
+ compile &cb
40
+ else
41
+ cb.call @path, nil, nil, nil
42
+ end
43
+ end
44
+
45
+ # Returns whether the source file has changed since it was last
46
+ # compiled.
47
+ def needs_update?
48
+ File.new(source).mtime > @last_compiled
49
+ end
50
+
51
+ private
52
+ def tmp_path
53
+ Tempfile.new("slinky").path
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,12 @@
1
+ module Slinky
2
+ module CoffeeCompiler
3
+ Server.register_compiler self,
4
+ :inputs => ["coffee"],
5
+ :outputs => ["js"]
6
+
7
+ def CoffeeCompiler::command from, to
8
+ root = File.dirname(__FILE__)
9
+ %Q?#{root}/coffee-helper "#{from}" "#{to}"?
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ coffee --compile --print $1 > $2
@@ -0,0 +1,11 @@
1
+ module Slinky
2
+ module HamlCompiler
3
+ Server.register_compiler self,
4
+ :inputs => ["haml"],
5
+ :outputs => ["html"]
6
+
7
+ def HamlCompiler::command from, to
8
+ %Q?haml "#{from}" "#{to}"?
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Slinky
2
+ module SassCompiler
3
+ Server.register_compiler self,
4
+ :inputs => ["sass", "scss"],
5
+ :outputs => ["css"]
6
+
7
+ def SassCompiler::command from, to
8
+ %Q?sass "#{from}:#{to}"?
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,67 @@
1
+ require 'rubygems'
2
+ require 'eventmachine'
3
+
4
+ if RUBY_VERSION < "1.8.7"
5
+ def __method__
6
+ caller = /`(.*)'/
7
+ Kernel.caller.first.split(caller).last.to_sym
8
+ end
9
+ end
10
+
11
+ def log *message
12
+ p [Time.now, *message]
13
+ end
14
+
15
+ module EventMachine
16
+ def self.popen3(*args)
17
+ new_stderr = $stderr.dup
18
+ rd, wr = IO::pipe
19
+ $stderr.reopen wr
20
+ connection = EM.popen(*args)
21
+ $stderr.reopen new_stderr
22
+ EM.attach rd, Popen3StderrHandler, connection
23
+ connection
24
+ end
25
+
26
+ class Popen3StderrHandler < EventMachine::Connection
27
+ def initialize(connection)
28
+ @connection = connection
29
+ end
30
+
31
+ def receive_data(data)
32
+ @connection.receive_stderr(data)
33
+ end
34
+ end
35
+ end
36
+
37
+ class ProcessHandler < EventMachine::Connection
38
+ def initialize cb
39
+ @cb = cb
40
+ @stdout = []
41
+ @stderr = []
42
+ end
43
+
44
+ def receive_data data
45
+ @stdout << data
46
+ end
47
+
48
+ def receive_stderr data
49
+ @stderr << data
50
+ end
51
+
52
+ def unbind
53
+ @cb.call @stdout.join(''), @stderr.join(''), get_status if @cb
54
+ end
55
+ end
56
+
57
+ def EventMachine::system3 cmd, *args, &cb
58
+ cb ||= args.pop if args.last.is_a? Proc
59
+ init = args.pop if args.last.is_a? Proc
60
+
61
+ # merge remaining arguments into the command
62
+ cmd = ([cmd] + args.map{|a|a.to_s.dump}).join(' ')
63
+
64
+ EM.get_subprocess_pid(EM.popen3(cmd, ProcessHandler, cb) do |c|
65
+ init[c] if init
66
+ end.signature)
67
+ end
@@ -0,0 +1,12 @@
1
+ module Slinky
2
+ class Runner
3
+ class << self
4
+ def run
5
+ EM::run {
6
+ EM::start_server "0.0.0.0", 5323, Slinky::Server
7
+ puts "Started static file server on port 5323"
8
+ }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,115 @@
1
+ module Slinky
2
+ class Server < EventMachine::Connection
3
+ include EM::HttpServer
4
+
5
+ @compilers = []
6
+ @compilers_by_ext = {}
7
+
8
+
9
+ @files = {}
10
+
11
+ class << self
12
+ def register_compiler klass, options
13
+ options[:klass] = klass
14
+ @compilers << options
15
+ options[:outputs].each do |output|
16
+ @compilers_by_ext[output] ||= []
17
+ @compilers_by_ext[output] << options
18
+ end
19
+ end
20
+
21
+ def compilers_by_ext
22
+ @compilers_by_ext
23
+ end
24
+ end
25
+
26
+ def files
27
+ self.class.instance_variable_get(:@files)
28
+ end
29
+
30
+ EXTENSION_REGEX = /(^[\w\d\:\/\.]*)\.(\w+)/
31
+ def process_http_request
32
+ @resp = EventMachine::DelegatedHttpResponse.new(self)
33
+
34
+ _, _, _, _, _, path, _, query = URI.split @http_request_uri
35
+ path = path[1..-1] #get rid of the leading /
36
+ _, file, extension = path.match(EXTENSION_REGEX).to_a
37
+
38
+ compilers = self.class.compilers_by_ext
39
+
40
+ # Check if we've already seen this file. If so, we can skip a
41
+ # bunch of processing.
42
+ if files[path]
43
+ serve_compiled_file files[path]
44
+ return
45
+ end
46
+
47
+ # if there's a file extension and we have a compiler that
48
+ # outputs that kind of file, look for an input with the same
49
+ # name and an extension in our list
50
+ if extension && extension != "" && compilers[extension]
51
+ files_by_ext = {}
52
+ # find possible source files
53
+ Dir.glob("#{file}.*").each do |f|
54
+ _, _, ext = f.match(EXTENSION_REGEX).to_a
55
+ files_by_ext[ext] = f
56
+ end
57
+
58
+ cfile = nil
59
+ # find a compiler that outputs the request kind of file and
60
+ # which has an input file type that exists on the file system
61
+ compilers[extension].each do |c|
62
+ c[:inputs].each do |i|
63
+ if files_by_ext[i]
64
+ cfile = CompiledFile.new files_by_ext[i], c[:klass]
65
+ files[path] = cfile
66
+ break
67
+ end
68
+ end
69
+ break if cfile
70
+ end
71
+
72
+ if cfile
73
+ serve_compiled_file cfile
74
+ else
75
+ serve_file path
76
+ end
77
+ else
78
+ serve_file path
79
+ end
80
+ end
81
+
82
+ def serve_compiled_file cfile
83
+ cfile.file do |path, status, stdout, stderr|
84
+ if path
85
+ serve_file path
86
+ else
87
+ puts "Status: #{status.inspect}"
88
+ @resp.status = 500
89
+ @resp.content = "Error compiling #{cfile.source}:\n #{stdout}"
90
+ @resp.send_response
91
+ end
92
+ end
93
+ end
94
+
95
+ def serve_file path
96
+ if File.exists? path
97
+ size = File.size? path
98
+ if true || size < EventMachine::FileStreamer::MappingThreshold
99
+ s = File.open(path).read
100
+ @resp.content = s
101
+ @resp.send_response
102
+ else
103
+ stream_file_data path do
104
+ @resp.send_headers
105
+ @resp.send_trailer
106
+ end
107
+ end
108
+ else
109
+ @resp.status = 404
110
+ @resp.content = "File '#{path}' not found."
111
+ @resp.send_response
112
+ end
113
+ end
114
+ end
115
+ end
data/lib/slinky.rb ADDED
@@ -0,0 +1,22 @@
1
+ ROOT = File.expand_path(File.dirname(__FILE__))
2
+
3
+ require 'eventmachine'
4
+ require 'evma_httpserver'
5
+ require 'uri'
6
+ require 'tempfile'
7
+
8
+ require "#{ROOT}/slinky/em-popen3"
9
+ require "#{ROOT}/slinky/compiled_file"
10
+ require "#{ROOT}/slinky/server"
11
+ require "#{ROOT}/slinky/runner"
12
+
13
+ # load compilers
14
+ Dir.glob("#{ROOT}/slinky/compilers/*.rb").each{|compiler|
15
+ begin
16
+ require compiler
17
+ rescue
18
+ puts "Failed to load #{compiler}: #{$!}"
19
+ rescue LoadError
20
+ puts "Failed to load #{compiler}: syntax error"
21
+ end
22
+ }
data/slinky.gemspec ADDED
@@ -0,0 +1,82 @@
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 = %q{slinky}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["mwylde"]
12
+ s.date = %q{2011-03-11}
13
+ s.default_executable = %q{slinky}
14
+ s.description = %q{A static file server for rich javascript apps that automatically compiles SASS, HAML, CoffeeScript and more}
15
+ s.email = %q{mwylde@wesleyan.edu}
16
+ s.executables = ["slinky"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ "Gemfile",
24
+ "LICENSE.txt",
25
+ "README.md",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "bin/slinky",
29
+ "lib/slinky.rb",
30
+ "lib/slinky/compiled_file.rb",
31
+ "lib/slinky/compilers/coffee-compiler.rb",
32
+ "lib/slinky/compilers/coffee-helper",
33
+ "lib/slinky/compilers/haml-compiler.rb",
34
+ "lib/slinky/compilers/sass-compiler.rb",
35
+ "lib/slinky/em-popen3.rb",
36
+ "lib/slinky/runner.rb",
37
+ "lib/slinky/server.rb",
38
+ "slinky.gemspec",
39
+ "spec/slinky_spec.rb",
40
+ "spec/spec_helper.rb"
41
+ ]
42
+ s.homepage = %q{http://github.com/mwylde/slinky}
43
+ s.licenses = ["MIT"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.5.2}
46
+ s.summary = %q{Static file server for javascript apps}
47
+ s.test_files = [
48
+ "spec/slinky_spec.rb",
49
+ "spec/spec_helper.rb"
50
+ ]
51
+
52
+ if s.respond_to? :specification_version then
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.0"])
57
+ s.add_runtime_dependency(%q<eventmachine_httpserver>, [">= 0.2.0"])
58
+ s.add_development_dependency(%q<bacon>, [">= 0"])
59
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
60
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
61
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
62
+ s.add_development_dependency(%q<rcov>, [">= 0"])
63
+ else
64
+ s.add_dependency(%q<eventmachine>, [">= 0.12.0"])
65
+ s.add_dependency(%q<eventmachine_httpserver>, [">= 0.2.0"])
66
+ s.add_dependency(%q<bacon>, [">= 0"])
67
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
70
+ s.add_dependency(%q<rcov>, [">= 0"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<eventmachine>, [">= 0.12.0"])
74
+ s.add_dependency(%q<eventmachine_httpserver>, [">= 0.2.0"])
75
+ s.add_dependency(%q<bacon>, [">= 0"])
76
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
77
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
78
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
79
+ s.add_dependency(%q<rcov>, [">= 0"])
80
+ end
81
+ end
82
+
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Slinky" do
4
+ it "fails" do
5
+ should.flunk "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,16 @@
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 'bacon'
11
+
12
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ require 'static-runner'
15
+
16
+ Bacon.summary_on_exit
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: slinky
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - mwylde
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-03-11 00:00:00 -05:00
14
+ default_executable: slinky
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: eventmachine
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.12.0
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: eventmachine_httpserver
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 0.2.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: bacon
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: yard
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: 0.6.0
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: bundler
62
+ requirement: &id005 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: 1.0.0
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: jeweler
73
+ requirement: &id006 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: 1.5.2
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: rcov
84
+ requirement: &id007 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: *id007
93
+ description: A static file server for rich javascript apps that automatically compiles SASS, HAML, CoffeeScript and more
94
+ email: mwylde@wesleyan.edu
95
+ executables:
96
+ - slinky
97
+ extensions: []
98
+
99
+ extra_rdoc_files:
100
+ - LICENSE.txt
101
+ - README.md
102
+ files:
103
+ - .document
104
+ - Gemfile
105
+ - LICENSE.txt
106
+ - README.md
107
+ - Rakefile
108
+ - VERSION
109
+ - bin/slinky
110
+ - lib/slinky.rb
111
+ - lib/slinky/compiled_file.rb
112
+ - lib/slinky/compilers/coffee-compiler.rb
113
+ - lib/slinky/compilers/coffee-helper
114
+ - lib/slinky/compilers/haml-compiler.rb
115
+ - lib/slinky/compilers/sass-compiler.rb
116
+ - lib/slinky/em-popen3.rb
117
+ - lib/slinky/runner.rb
118
+ - lib/slinky/server.rb
119
+ - slinky.gemspec
120
+ - spec/slinky_spec.rb
121
+ - spec/spec_helper.rb
122
+ has_rdoc: true
123
+ homepage: http://github.com/mwylde/slinky
124
+ licenses:
125
+ - MIT
126
+ post_install_message:
127
+ rdoc_options: []
128
+
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ hash: -191776360948002665
137
+ segments:
138
+ - 0
139
+ version: "0"
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ none: false
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: "0"
146
+ requirements: []
147
+
148
+ rubyforge_project:
149
+ rubygems_version: 1.5.2
150
+ signing_key:
151
+ specification_version: 3
152
+ summary: Static file server for javascript apps
153
+ test_files:
154
+ - spec/slinky_spec.rb
155
+ - spec/spec_helper.rb