Browse files

implement

  • Loading branch information...
0 parents commit 040d6e975d512c3e6dbf9a339e83f870089223ec @maccman committed Jun 4, 2012
17 .gitignore
@@ -0,0 +1,17 @@
+*.gem
+*.rbc
+.bundle
+.config
+.yardoc
+Gemfile.lock
+InstalledFiles
+_yardoc
+coverage
+doc/
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
4 Gemfile
@@ -0,0 +1,4 @@
+source 'https://rubygems.org'
+
+# Specify your gem's dependencies in catapult.gemspec
+gemspec
22 LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Alex MacCaw
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 README.md
@@ -0,0 +1,29 @@
+# Catapult
+
+TODO: Write a gem description
+
+## Installation
+
+Add this line to your application's Gemfile:
+
+ gem 'catapult'
+
+And then execute:
+
+ $ bundle
+
+Or install it yourself as:
+
+ $ gem install catapult
+
+## Usage
+
+TODO: Write usage instructions here
+
+## Contributing
+
+1. Fork it
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Added some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
2 Rakefile
@@ -0,0 +1,2 @@
+#!/usr/bin/env rake
+require "bundler/gem_tasks"
15 bin/catapult
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+require 'rubygems'
+require 'bundler/setup'
+require 'catapult'
+Bundler.require if File.exists?('Gemfile')
+
+begin
+ require 'catapult/cli'
+ Catapult::CLI.start
+rescue Interrupt => e
+ puts "\nQuitting..."
+ exit 1
+rescue SystemExit => e
+ exit e.status
+end
26 catapult.gemspec
@@ -0,0 +1,26 @@
+# -*- encoding: utf-8 -*-
+require File.expand_path('../lib/catapult/version', __FILE__)
+
+Gem::Specification.new do |gem|
+ gem.authors = ["Alex MacCaw"]
+ gem.email = ["maccman@gmail.com"]
+ gem.description = %q{TODO: Write a gem description}
+ gem.summary = %q{TODO: Write a gem summary}
+ gem.homepage = ""
+
+ gem.files = `git ls-files`.split($\)
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
+ gem.name = "catapult"
+ gem.require_paths = ["lib"]
+ gem.version = Catapult::VERSION
+
+ gem.add_dependency 'rack', '~> 1.4.1'
+ gem.add_dependency 'sprockets', '~> 2.4.3'
+ gem.add_dependency 'sprockets-commonjs', '= 0.0.6.pre'
+ gem.add_dependency 'listen', '~> 0.4.2'
+ gem.add_dependency 'stylus', '~> 0.6.2'
+ gem.add_dependency 'coffee-script', '~> 2.2.0'
+ gem.add_dependency 'thor', '~> 0.15.2'
+ gem.add_dependency 'thin', '~> 1.3.1'
+end
2 example/assets/javascripts/application.module.coffee
@@ -0,0 +1,2 @@
+module.exports = ->
+ 'A coffee file'
68 example/public/assets/application.module.js
@@ -0,0 +1,68 @@
+(function() {
+ if (!this.require) {
+ var modules = {}, cache = {};
+
+ var require = function(name, root) {
+ var path = expand(root, name), indexPath = expand(path, './index'), module, fn;
+ module = cache[path] || cache[indexPath];
+ if (module) {
+ return module;
+ } else if (fn = modules[path] || modules[path = indexPath]) {
+ module = {id: path, exports: {}};
+ cache[path] = module.exports;
+ fn(module.exports, function(name) {
+ return require(name, dirname(path));
+ }, module);
+ return cache[path] = module.exports;
+ } else {
+ throw 'module ' + name + ' not found';
+ }
+ };
+
+ var expand = function(root, name) {
+ var results = [], parts, part;
+ // If path is relative
+ if (/^\.\.?(\/|$)/.test(name)) {
+ parts = [root, name].join('/').split('/');
+ } else {
+ parts = name.split('/');
+ }
+ for (var i = 0, length = parts.length; i < length; i++) {
+ part = parts[i];
+ if (part == '..') {
+ results.pop();
+ } else if (part != '.' && part != '') {
+ results.push(part);
+ }
+ }
+ return results.join('/');
+ };
+
+ var dirname = function(path) {
+ return path.split('/').slice(0, -1).join('/');
+ };
+
+ this.require = function(name) {
+ return require(name, '');
+ };
+
+ this.require.define = function(bundle) {
+ for (var key in bundle) {
+ modules[key] = bundle[key];
+ }
+ };
+
+ this.require.modules = modules;
+ this.require.cache = cache;
+ }
+
+ return this.require;
+}).call(this);
+this.require.define({"application":function(exports, require, module){(function() {
+
+ module.exports = function() {
+ return 'A coffee file 2';
+ };
+
+}).call(this);
+;}});
60 example/public/assets/sprockets/commonjs.js
@@ -0,0 +1,60 @@
+(function() {
+ if (!this.require) {
+ var modules = {}, cache = {};
+
+ var require = function(name, root) {
+ var path = expand(root, name), indexPath = expand(path, './index'), module, fn;
+ module = cache[path] || cache[indexPath];
+ if (module) {
+ return module;
+ } else if (fn = modules[path] || modules[path = indexPath]) {
+ module = {id: path, exports: {}};
+ cache[path] = module.exports;
+ fn(module.exports, function(name) {
+ return require(name, dirname(path));
+ }, module);
+ return cache[path] = module.exports;
+ } else {
+ throw 'module ' + name + ' not found';
+ }
+ };
+
+ var expand = function(root, name) {
+ var results = [], parts, part;
+ // If path is relative
+ if (/^\.\.?(\/|$)/.test(name)) {
+ parts = [root, name].join('/').split('/');
+ } else {
+ parts = name.split('/');
+ }
+ for (var i = 0, length = parts.length; i < length; i++) {
+ part = parts[i];
+ if (part == '..') {
+ results.pop();
+ } else if (part != '.' && part != '') {
+ results.push(part);
+ }
+ }
+ return results.join('/');
+ };
+
+ var dirname = function(path) {
+ return path.split('/').slice(0, -1).join('/');
+ };
+
+ this.require = function(name) {
+ return require(name, '');
+ };
+
+ this.require.define = function(bundle) {
+ for (var key in bundle) {
+ modules[key] = bundle[key];
+ }
+ };
+
+ this.require.modules = modules;
+ this.require.cache = cache;
+ }
+
+ return this.require;
+}).call(this);
3 example/public/index.html
@@ -0,0 +1,3 @@
+<h1>Hello world</h1>
+
+<script src="/assets/application.module.js" type="text/javascript" charset="utf-8"></script>
52 lib/catapult.rb
@@ -0,0 +1,52 @@
+require 'pathname'
+require 'sprockets'
+require 'sprockets/commonjs'
+require 'stylus/tilt'
+require 'stylus/import_processor'
+require 'coffee_script'
+
+module Catapult
+ autoload :CLI, 'catapult/cli'
+ autoload :TryStatic, 'catapult/try_static'
+
+ def self.root
+ @root ||= Pathname('.').expand_path
+ end
+
+ def self.environment
+ @environment ||= begin
+ env = Sprockets::Environment.new(root)
+
+ env.append_path(root.join('assets', 'javascripts'))
+ env.append_path(root.join('assets', 'stylesheets'))
+ env.append_path(root.join('assets', 'images'))
+
+ env.append_path(root.join('vendor', 'assets', 'javascripts'))
+ env.append_path(root.join('vendor', 'assets', 'stylesheets'))
+
+ env.append_path(root.join('browser_modules'))
+
+ env.register_engine '.styl', Tilt::StylusTemplate
+ env.register_preprocessor 'text/css', Stylus::ImportProcessor
+
+ env
+ end
+ end
+
+ def self.app
+ app = Rack::Builder.new do
+ map '/assets' do
+ run Catapult.environment
+ end
+
+ use Catapult::TryStatic,
+ :root => Catapult.root.join('public'),
+ :urls => %w[/],
+ :try => ['.html', 'index.html', '/index.html']
+
+ run lambda {|env|
+ [404, {}, ['Not found']]
+ }
+ end
+ end
+end
51 lib/catapult/cli.rb
@@ -0,0 +1,51 @@
+require 'pathname'
+require 'fileutils'
+require 'listen'
+require 'rack'
+require 'thor'
+
+module Catapult
+ class CLI < Thor
+
+ desc 'build', 'Build project'
+
+ def build
+ target = Pathname('./public/assets')
+
+ puts "Building: #{Catapult.root}"
+
+ Catapult.environment.each_logical_path do |logical_path|
+ if asset = Catapult.environment.find_asset(logical_path)
+ filename = target.join(logical_path)
+ FileUtils.mkpath(filename.dirname)
+ puts "Write asset: #{filename}"
+ asset.write_to(filename)
+ end
+ end
+ end
+
+ desc 'serve', 'Serve up project'
+
+ method_option :port, :aliases => '-p', :desc => 'Port'
+
+ def serve
+ Rack::Server.start(
+ :Port => options[:port] || 9292,
+ :app => Catapult.app
+ )
+ end
+
+ desc 'watch', 'build project whenever it changes'
+
+ def watch
+ puts "Watching: #{Catapult.root}"
+
+ build
+
+ paths = Catapult.environment.paths
+ paths = paths.select {|p| File.exists?(p) }
+
+ Listen.to(*paths) { build }
+ end
+ end
+end
36 lib/catapult/try_static.rb
@@ -0,0 +1,36 @@
+module Catapult
+ # The Rack::TryStatic middleware delegates requests to Rack::Static middleware
+ # trying to match a static file
+ #
+ # Examples
+ #
+ # use Rack::TryStatic,
+ # :root => "public", # static files root dir
+ # :urls => %w[/], # match all requests
+ # :try => ['.html', 'index.html', '/index.html'] # try these postfixes sequentially
+ #
+ # uses same options as Rack::Static with extra :try option which is an array
+ # of postfixes to find desired file
+
+ class TryStatic
+
+ def initialize(app, options)
+ @app = app
+ @try = ['', *options[:try]]
+ @static = ::Rack::Static.new(
+ lambda { |_| [404, {}, []] },
+ options
+ )
+ end
+
+ def call(env)
+ orig_path = env['PATH_INFO']
+ found = nil
+ @try.each do |path|
+ resp = @static.call(env.merge!({'PATH_INFO' => orig_path + path}))
+ break if 404 != resp[0] && found = resp
+ end
+ found or @app.call(env.merge!('PATH_INFO' => orig_path))
+ end
+ end
+end
3 lib/catapult/version.rb
@@ -0,0 +1,3 @@
+module Catapult
+ VERSION = '0.0.1'
+end

0 comments on commit 040d6e9

Please sign in to comment.