spar 0.2.7 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/README.md +272 -1
  2. data/bin/spar +30 -1
  3. data/lib/spar.rb +128 -7
  4. data/lib/spar/assets/404.jpg +0 -0
  5. data/lib/spar/assets/500.jpg +0 -0
  6. data/lib/spar/cli.rb +75 -22
  7. data/lib/spar/compiled_asset.rb +90 -0
  8. data/lib/spar/compiler.rb +74 -0
  9. data/lib/spar/compressor.rb +18 -0
  10. data/lib/spar/deployers/cloudfront_deployer.rb +33 -0
  11. data/lib/spar/deployers/deployer.rb +26 -0
  12. data/lib/spar/deployers/local_deployer.rb +15 -0
  13. data/lib/spar/deployers/s3_deployer.rb +75 -0
  14. data/lib/spar/directive_processor.rb +36 -0
  15. data/lib/spar/exceptions.rb +330 -0
  16. data/lib/spar/generators/templates/{README → base/README} +0 -0
  17. data/lib/spar/generators/templates/base/config.yml +12 -0
  18. data/lib/spar/generators/templates/pages/haml/app/pages/index.html.haml +11 -0
  19. data/lib/spar/generators/templates/pages/html/app/pages/index.html +16 -0
  20. data/lib/spar/generators/templates/{app/assets/javascripts/javascript.js.coffee → scripts/coffee/app/javascripts/application.js.coffee} +6 -3
  21. data/lib/spar/generators/templates/scripts/js/app/javascripts/application.js +11 -0
  22. data/lib/spar/generators/templates/styles/css/app/stylesheets/application.css +18 -0
  23. data/lib/spar/generators/templates/{app/assets → styles/sass/app}/stylesheets/application.css.sass +8 -4
  24. data/lib/spar/helpers.rb +31 -102
  25. data/lib/spar/not_found.rb +64 -0
  26. data/lib/spar/rewrite.rb +29 -0
  27. data/lib/spar/static.rb +46 -0
  28. data/lib/spar/tasks.rb +8 -13
  29. data/lib/spar/version.rb +1 -1
  30. metadata +261 -66
  31. data/lib/spar/assets.rb +0 -78
  32. data/lib/spar/base.rb +0 -54
  33. data/lib/spar/css_compressor.rb +0 -17
  34. data/lib/spar/deployer.rb +0 -198
  35. data/lib/spar/generators/application.rb +0 -42
  36. data/lib/spar/generators/templates/Gemfile +0 -3
  37. data/lib/spar/generators/templates/Rakefile +0 -8
  38. data/lib/spar/generators/templates/app/views/index.haml +0 -7
  39. data/lib/spar/generators/templates/config.ru +0 -9
  40. data/lib/spar/generators/templates/config/application.rb +0 -12
  41. data/lib/spar/generators/templates/script/server +0 -1
  42. data/lib/spar/static_compiler.rb +0 -91
data/README.md CHANGED
@@ -1 +1,272 @@
1
- Docs Coming Soon!
1
+ # Introduction
2
+
3
+ Spar, the *Single Page Application Rocketship*, is an opinionated framework that aims to ease single-page web-app development by addressing major challenges:
4
+
5
+ * Asset organization
6
+ * Compilation pipeline
7
+ * Build & deployment support
8
+
9
+ Additionally, Spar provides templates & example projects for either a bare-bones project, or one with some of our favorite tools pre-included.
10
+
11
+ Under the hood, Spar is a Sprockets-based, Rails-derived project. Spar uses Sprockets to provide a powerful asset-pipeline, while stripping out legacy web-app support and introducing tools & patterns specific to single-page apps.
12
+
13
+ # Requirements
14
+
15
+ * Ruby 1.9.2 or greater (preferably 1.9.3).
16
+
17
+ # Installing Spar
18
+
19
+ ```bash
20
+ $ gem install spar
21
+ ````
22
+
23
+ If using `rbenv`:
24
+
25
+ ```bash
26
+ $ rbenv rehash
27
+ ```
28
+
29
+ # Getting Started
30
+
31
+ Issue the following command to create a new Spar project:
32
+
33
+ ```bash
34
+ $ spar new myapp
35
+ $ cd myapp
36
+ $ spar server
37
+ ```
38
+ Your app will now be available at [http://localhost:8888](http://localhost:8888)
39
+
40
+ # Organization
41
+
42
+ Spar apps are organized into the following folders and files:
43
+
44
+ /app #Compiled assets that make your app
45
+ /images
46
+ /javascripts
47
+ application.js.coffee #Your main JS output
48
+ /stylesheets
49
+ application.css.sass #Your main CSS output
50
+ /pages
51
+ index.html.haml #Your single, root HTML page
52
+
53
+ /static #File in here will be available to your application, but not managed as assets.
54
+ /downloads #File in here will include a 'Content-Disposition: attachment;' header if deployed to S3
55
+
56
+ /vendor #Put external libraries like jquery or bootstrap here
57
+ /javascripts
58
+ /stylesheets
59
+
60
+ config.yml #ENV settings for development, staging, production
61
+ README #your project's README
62
+
63
+ # Configuration
64
+
65
+ `config.yml` defines your project's configuration for different environments. You may define any properties you like, which are available to you in all your asset files.
66
+
67
+ These settings may be overriden on a per-environment basis for `development`, `staging`, and `production` like so:
68
+
69
+ ```yaml
70
+ default:
71
+ debug: true
72
+ my_app_name: My App!
73
+ my_api: http://localhost:8080
74
+
75
+ staging:
76
+ debug: false
77
+
78
+ production:
79
+ debug: false
80
+ compress: true
81
+ my_api: http://production-api.mysite.com
82
+ ```
83
+
84
+ Spar respects the following known configuration options:
85
+
86
+ - `debug`: true/false, includes JS files individually for easier debugging
87
+ - `digest`: true/false, adds MD5 hashes to end of filenames for proper cache busting in deploys
88
+ - `compress`: true/false, JS and CSS compression (uglify, and yahoo UI CSS compressor)
89
+
90
+ # Asset Pipeline
91
+
92
+ All asset files in the `app` directory are transformed through the Spar asset pipeline. Transformation first occurs for configuration properties defined in `config.yml`, followed by JS/CSS asset-compilation and composition.
93
+
94
+ ## Configuration Property Replacement
95
+
96
+ First, configuration property substitution takes place according to your `config.yml` file. For instance, if your `index.html.haml` looks like this:
97
+
98
+ ```haml
99
+ %html
100
+ %head
101
+ %title [{ my_app_name }]
102
+ ```
103
+ it transforms to become:
104
+
105
+ ```haml
106
+ %html
107
+ %head
108
+ %title My App!
109
+ ```
110
+
111
+ ## Compilation
112
+
113
+ After Spar performs configuration replacement, it then process files according to their extensions.
114
+
115
+ Inlcuded with Spar are transformations from:
116
+
117
+ - `file.html.haml` => `file.html`
118
+ - `file.js.coffee` => `file.js`
119
+ - `file.css.sass` => `file.css`
120
+ - `file.css.less` => `file.less`
121
+
122
+ ## Dependency Management
123
+
124
+ Multiple Javascript (or CSS) files can be merged into a single file using the `require` and `require_tree` pre-processor directives.
125
+
126
+ If you want to serve one file, say `application.js`, that includes the content of multiple JS files, you may define an `application.js.coffee` like so:
127
+
128
+ ```coffeescript
129
+ # This file will be compiled into application.js, which
130
+ # will include all the files below required below
131
+
132
+ # The require directive can include individual file assets
133
+ # For instance, to include the compiled output of utils.js.coffee
134
+ #= require utils
135
+
136
+ # You can also recursively includes entire directories
137
+ # using the require_tree directive
138
+ #= require_tree ./controllers
139
+ #= require_tree ./models
140
+ #= require_tree ./views
141
+ ```
142
+ Stylesheet files are composed similarly, however directives should be placed in CSS/SASS comments appropriately:
143
+
144
+ ```css
145
+ /*= require buttons.css */
146
+ ```
147
+
148
+ ## Deploy Directive
149
+ Most Spar apps will compile into a single `application.js` and `application.css` file, each including the `deploy` directive to ensure it is deployed.
150
+
151
+ If you wish to deploy additional root-level asset files, you may instruct Spar to do so by adding a `deploy` directive at the top of the file like so:
152
+
153
+ ```coffeescript
154
+ #= deploy
155
+ ```
156
+
157
+ Or, in CSS:
158
+
159
+ ```css
160
+ /*= deploy */
161
+ ```
162
+ You only need to do this for additional root-level Javascript and CSS based files, as Spar deploys all images, pages, and static files automatically.
163
+
164
+ # Example Spar Applications
165
+
166
+ For your reference, and to build on top of, we've created two example applications using Spar.
167
+
168
+ The first is the quintessential TODO application as popularized by [addyosmani](http://addyosmani.github.com/todomvc/). The second, is a bootstrap application containing some of our favorite tools to kick-start the pretty (jQuery, Backbone, and Twitter Bootstrap).
169
+
170
+ Both can be found at our [spar-examples](https://github.com/BoundlessLearning/spar-examples) repo.
171
+
172
+ # Deploying Your Spar App
173
+
174
+ Spar supports three different deployment methods out of the box:
175
+
176
+ * `local`: Deploy your app to a directory local to your computer.
177
+ * `s3`: Deploy your app to an AWS S3 bucket.
178
+ * `cloudfront`: Deploy your app to an AWS S3 bucket and invalidate a Cloudfront distribution.
179
+
180
+ To deploy your app, run:
181
+
182
+ ```bash
183
+ spar deploy poduction
184
+ ```
185
+
186
+ You can pass any environment name to the deploy command, typically `staging` or `production`.
187
+
188
+ ## Local Deployment
189
+
190
+ To deploy to a local directory, setup your `config.yml` file environments like so:
191
+
192
+ ```yaml
193
+ default:
194
+ debug: true
195
+
196
+ staging:
197
+ deploy_strategy: local
198
+ deploy_path: compiled/staging
199
+
200
+ production:
201
+ deploy_strategy: local
202
+ deploy_path: compiled/production
203
+ ```
204
+
205
+ The `deploy_path` may be either a relative path in your application or a global path on your computer.
206
+
207
+ ## S3 Deployment
208
+
209
+ To deploy to an S3 bucket, setup your environments like so:
210
+
211
+ ```yaml
212
+ production:
213
+ deploy_strategy: s3
214
+ aws_key: "my_access_key"
215
+ aws_secret: "my+super+secret+access+key"
216
+ deploy_bucket: "mysite.test.com"
217
+ ```
218
+
219
+ You'll need to enter your own credentials. You can find your S3 credentials on the [AWS Security Credentials](https://portal.aws.amazon.com/gp/aws/securityCredentials) page.
220
+
221
+ Next, you'll need visit the [AWS S3 Console](https://console.aws.amazon.com/s3/home) and create a bucket to host your app. We suggest using the same as your fully qualified domain name. You should not use this bucket for anything else.
222
+
223
+ ![click here](http://spar-screenshots.s3.amazonaws.com/s3_click_here.png)
224
+
225
+ ![create bucket](http://spar-screenshots.s3.amazonaws.com/s3_create_bucket.png)
226
+
227
+ Next, you'll need to turn on [S3 Website Hosting](http://aws.typepad.com/aws/2011/02/host-your-static-website-on-amazon-s3.html) in the S3 console.
228
+
229
+ ![bucket properties](http://spar-screenshots.s3.amazonaws.com/s3_bucket_properties.png)
230
+
231
+ ![enable website](http://spar-screenshots.s3.amazonaws.com/s3_enable_website.png)
232
+
233
+ You'll need to create a new `CNAME` record. How this works is up to your hosting provider, but it should look something like this.
234
+
235
+ app.example.com. IN CNAME app.example.com.s3-website-us-east-1.amazonaws.com.
236
+
237
+ ### About Logging
238
+
239
+ You'll probably want to be able to log requests to your site. Even though your app uses cutting edge webscale tools like Airbrake, Loggly, Google Analytics, MixPanel, et al, eventually you'll want to know how many people hit you with IE6 or NoScript, and you gave them the middle finger.
240
+
241
+ Create a bucket log using the [AWS S3 Console](https://console.aws.amazon.com/s3/home). Give it a name like `logs.example.com` and update either your app's CloudFront distribution or your app's S3 bucket to write its log files to this log bucket.
242
+
243
+ ![enable logging](http://spar-screenshots.s3.amazonaws.com/s3_enable_logging.png)
244
+
245
+
246
+ ## CloudFront Deployment
247
+
248
+ Cloudfront deployment is very similar to S3 deployment, but you need to add a `cloudfront_distribution` property to your config file:
249
+
250
+ ```yaml
251
+ production:
252
+ deploy_strategy: cloudfront
253
+ aws_key: "my_access_key"
254
+ aws_secret: "my+super+secret+access+key"
255
+ deploy_bucket: "mysite.test.com"
256
+ cloudfront_distribution: "distribution+id"
257
+ ```
258
+ Cloudfront will turn your fast site into a *really* fast site. From the [AWS CloudFront Console](https://console.aws.amazon.com/cloudfront/home), create a new distribution *with the website form of your bucket name as the origin* and save the ID in your config.yml.
259
+
260
+ Take note of the **Domain Name** field (something like `d242ood0j0gl2v.cloudfront.net`). You will need to replace the CNAME you created earlier.
261
+
262
+ app.example.com. IN CNAME d242ood0j0gl2v.cloudfront.net.
263
+
264
+ Now, every time you deploy, Spar will automatically issue CloudFront invalidation requests for index.html (and anything else without a hash value). CloudFront invalidations usually take around 8 minutes, but they can take quite a bit lot longer when Amazon is having problems.
265
+
266
+ # Issues & Bugs
267
+
268
+ Please use our Github [issue tracker](https://github.com/BoundlessLearning/spar/issues) for Spar.
269
+
270
+ # License
271
+
272
+ Spar is licensed under the terms of the MIT License, see the included LICENSE file.
data/bin/spar CHANGED
@@ -1,3 +1,32 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "spar/cli"
3
+ require 'rbconfig'
4
+
5
+ if RUBY_VERSION < '1.9.2'
6
+ desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
7
+ abort <<-end_message
8
+
9
+ Spar requires Ruby 1.9.2+.
10
+
11
+ You're running
12
+ #{desc}
13
+
14
+ Please upgrade to continue.
15
+
16
+ end_message
17
+ end
18
+ Signal.trap("INT") { puts; exit(1) }
19
+
20
+ require 'bundler/setup'
21
+ require 'spar'
22
+ Bundler.require if File.exists?('Gemfile')
23
+
24
+ begin
25
+ require 'spar/cli'
26
+ Spar::CLI.start
27
+ rescue Interrupt => e
28
+ puts "\nStopping..."
29
+ exit 1
30
+ rescue SystemExit => e
31
+ exit e.status
32
+ end
data/lib/spar.rb CHANGED
@@ -1,16 +1,137 @@
1
+ require 'rack'
2
+ require 'pathname'
3
+ require 'sprockets'
4
+ require 'haml'
5
+
1
6
  module Spar
2
7
  autoload :Version, 'spar/version'
3
- autoload :Base, 'spar/base'
4
- autoload :Assets, 'spar/assets'
5
- autoload :StaticCompiler, 'spar/static_compiler'
8
+ autoload :CLI, 'spar/cli'
9
+ autoload :Rewrite, 'spar/rewrite'
10
+ autoload :Exceptions, 'spar/exceptions'
11
+ autoload :DirectiveProcessor, 'spar/directive_processor'
6
12
  autoload :Helpers, 'spar/helpers'
7
- autoload :CssCompressor, 'spar/css_compressor'
8
- autoload :Deployer, 'spar/deployer'
13
+ autoload :Compressor, 'spar/compressor'
14
+ autoload :Compiler, 'spar/compiler'
15
+ autoload :CompiledAsset, 'spar/compiled_asset'
16
+ autoload :Deployer, 'spar/deployers/deployer'
17
+ autoload :Assets, 'spar/assets'
18
+ autoload :Static, 'spar/static'
19
+ autoload :NotFound, 'spar/not_found'
20
+
21
+ DEFAULTS = {
22
+ 'digest' => false,
23
+ 'debug' => true,
24
+ 'compress' => false,
25
+ 'js_compressor' => {
26
+ 'mangle' => false
27
+ },
28
+ 'css_compressor' => {},
29
+ 'cache_control' => "public, max-age=#{60 * 60 * 24 * 7}"
30
+ }
31
+
32
+ def self.root
33
+ @root ||= begin
34
+ # Remove the line number from backtraces making sure we don't leave anything behind
35
+ call_stack = caller.map { |p| p.sub(/:\d+.*/, '') }
36
+ root_path = File.dirname(call_stack.detect { |p| p !~ %r[[\w.-]*/lib/spar|rack[\w.-]*/lib/rack] })
37
+
38
+ while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/config.yml")
39
+ parent = File.dirname(root_path)
40
+ root_path = parent != root_path && parent
41
+ end
42
+
43
+ root = File.exist?("#{root_path}/config.yml") ? root_path : Dir.pwd
44
+ raise "Could not find root path for #{self}" unless root
45
+
46
+ RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? Pathname.new(root).expand_path : Pathname.new(root).realpath
47
+ end
48
+ end
49
+
50
+ def self.environment=(environment)
51
+ @environment = environment
52
+ end
53
+
54
+ def self.environment
55
+ @environment ||= ENV['SPAR_ENV'] || ENV['RACK_ENV'] || 'development'
56
+ end
57
+
58
+ def self.assets
59
+ @assets ||= Spar::Assets.new
60
+ end
61
+
62
+ def self.static
63
+ @static ||= Spar::Static.new
64
+ end
65
+
66
+ def self.not_found
67
+ @not_found ||= Spar::NotFound.new
68
+ end
69
+
70
+ def self.sprockets
71
+ @sprockets ||= begin
72
+ env = Sprockets::Environment.new(root)
73
+
74
+ if settings['compress']
75
+ env.js_compressor = Compressor::JS.new
76
+ env.css_compressor = Compressor::CSS.new
77
+ end
78
+
79
+ child_folders = ['javascripts', 'stylesheets', 'images', 'pages', 'fonts']
80
+
81
+ for child_folder in child_folders
82
+ env.append_path(root.join('app', child_folder))
83
+ env.append_path(root.join('vendor', child_folder))
84
+ Gem.loaded_specs.each do |name, gem|
85
+ env.append_path(File.join(gem.full_gem_path, 'vendor', 'assets', child_folder))
86
+ env.append_path(File.join(gem.full_gem_path, 'app', 'assets', 'assets', child_folder))
87
+ end
88
+ end
89
+
90
+ env.append_path(root.join('components'))
9
91
 
10
- class << self
92
+ for path in (settings['paths'] || [])
93
+ env.append_path(root.join(*path.split('/')))
94
+ end
11
95
 
12
- attr_accessor :root, :assets
96
+ env.register_engine '.haml', Tilt::HamlTemplate
97
+ env.register_engine '.md', Tilt::BlueClothTemplate
98
+ env.register_engine '.textile', Tilt::RedClothTemplate
13
99
 
100
+ env.register_postprocessor 'text/css', Spar::DirectiveProcessor
101
+ env.register_postprocessor 'application/javascript', Spar::DirectiveProcessor
102
+ env.register_postprocessor 'text/html', Spar::DirectiveProcessor
103
+
104
+ env
105
+ end
106
+ end
107
+
108
+ def self.app
109
+ app = Rack::Builder.new do
110
+ use Spar::Rewrite
111
+ use Spar::Exceptions
112
+
113
+ run Rack::Cascade.new([Spar.static, Spar.sprockets, Spar.not_found])
114
+
115
+ use Rack::ContentType
116
+ end
117
+ end
118
+
119
+ def self.settings
120
+ @settings ||= load_config
14
121
  end
15
122
 
123
+ protected
124
+
125
+ def self.load_config
126
+ pathname = Pathname.new(Spar.root).join("config.yml")
127
+ begin
128
+ yaml = YAML.load_file(pathname)
129
+ settings = DEFAULTS.merge(yaml['default'] || {}).merge(yaml[environment] || {})
130
+ settings['environment'] = environment
131
+ settings
132
+ rescue => e
133
+ raise "Could not load the config.yml file: #{e.message}"
134
+ end
135
+ end
136
+
16
137
  end