linner 0.4.6 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 22e8e5dc49bf60b631d9932980705923d288eb05
4
- data.tar.gz: d528f466a6cf1f464a602b40fd205ea051f40b8c
3
+ metadata.gz: d8883d113979a23a06f305ffaa96e7c224e3e08d
4
+ data.tar.gz: eae9dcb29be6f8b59a5696cc11d84504abc7145d
5
5
  SHA512:
6
- metadata.gz: 7de696f89676b8d83d6848cab9230e72bb4ad369dc2e537beefb5b723f6be54cca8f984c1d5447049a646a80cc27c1566b42f0dfeb3559d258581e3c42a555bc
7
- data.tar.gz: 8b9db856716048223a35fbd7117ce861ff7d9d3d66a449f1648316c8ed4f87ae056cee7930398d54709e1cef7774e3fbd0ebdd27d6eb66e8216bcaec2811862c
6
+ metadata.gz: a9e63c8c9c462d9faa0aecc39885f5e74429ee366d773eccc09c02d99b408628031d3ef4c6dd5429b3f86e90333ebd6b88c88d04bd8ad10b6af4d6e4d1d47cf1
7
+ data.tar.gz: 1d4fd2a6f5e681f9a0c7b361e5fde514a2efbfa32850b0f877c816aeb552db1baca5238a23afef2a429b63dadea92103640df9da0ac4b5747acf4b7fe9888b84
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ v 0.5.0
2
+ - linner command now provides `check` and `install` commands to check and install vendor dependencies
3
+
1
4
  v 0.4.6
2
5
  - compat terminal-notifier with OS X mavericks
3
6
 
data/README.md CHANGED
@@ -13,9 +13,10 @@ Linner is a full-featured HTML5 application assembler.
13
13
  * Fast!
14
14
  * Supports `Sass`, `Compass` and `Coffee`.
15
15
  * Supports OS X Lion and Mountaion Lion Notifications.
16
- * Supports Modular Javascript, All your code will be wrap by `cmd`.
16
+ * Supports Modular Javascript, All your code will be wrapped by `cmd`.
17
17
  * Supports `concat` code by `config file` not `directive processor`.
18
18
  * Supports `copy` code from `src` to `dest`.
19
+ * Supports `precompile` Javascript Templates from `src` to `desc`
19
20
  * Supports Real-time `concat` by `$ linner watch`.
20
21
  * Supports `compress` by `$ linner build`.
21
22
  * Supports `LiveReload` with [LiveReload Chrome Extention](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei).
@@ -4,6 +4,14 @@
4
4
 
5
5
  Create new brunch project.
6
6
 
7
+ ## `linner check`
8
+
9
+ Check linner bundles
10
+
11
+ ## `linner install`
12
+
13
+ Install linner bundles
14
+
7
15
  ## `linner watch`
8
16
 
9
17
  Watch linner directory and rebuild if something changed.
@@ -51,6 +51,8 @@ the default configuration defines four groups: `scripts`, `styles`, `images` and
51
51
 
52
52
  `copy` defines copy strategy of files in Linner. The `Dir.glob` of `value` will be copy to `key` folder.
53
53
 
54
+ `precompile` defines precompile strategy of javascript templates for Linner. The `Dir.glob` of `value` will be concat to `key`
55
+
54
56
  `order` defines the order of this group files, and It's very useful when you `concat` your files. for example:
55
57
 
56
58
  ```yaml
@@ -102,3 +104,25 @@ Default:
102
104
  ```yaml
103
105
  notification: true
104
106
  ```
107
+
108
+ ## `bundles`
109
+
110
+ `bundles` defines application's library dependencies, the dependencies will be copied to `vendor` folder.
111
+
112
+ For example:
113
+
114
+ ```yaml
115
+ bundles:
116
+ "jquery.js":
117
+ version: "1.10.2"
118
+ url: "http://code.jquery.com/jquery-1.10.2.js"
119
+ "underscore.js":
120
+ version: "1.5.2"
121
+ url: https://raw.github.com/jashkenas/underscore/1.5.2/underscore.js
122
+ "backbone.js":
123
+ version: "1.1.0"
124
+ url: "https://raw.github.com/jashkenas/backbone/1.1.0/backbone.js"
125
+ "handlebars.js":
126
+ version: "1.0.0"
127
+ url: "https://raw.github.com/wycats/handlebars.js/1.0.0/dist/handlebars.js"
128
+ ```
@@ -5,6 +5,7 @@ require "linner/command"
5
5
  require "linner/asset"
6
6
  require "linner/cache"
7
7
  require "linner/helper"
8
+ require "linner/bundler"
8
9
  require "linner/reactor"
9
10
  require "linner/wrapper"
10
11
  require "linner/template"
@@ -65,6 +66,9 @@ module Linner
65
66
  end
66
67
 
67
68
  def perform(*asset)
69
+ env.groups.each do |config|
70
+ precompile(config) if config["precompile"]
71
+ end
68
72
  env.groups.each do |config|
69
73
  copy(config) if config["copy"]
70
74
  concat(config) if config["concat"]
@@ -72,7 +76,7 @@ module Linner
72
76
  revision if compile? and env.revision
73
77
  end
74
78
 
75
- private
79
+ private
76
80
  def concat(config)
77
81
  config["concat"].each_with_index do |pair, index|
78
82
  dest, pattern, order = pair.first, pair.last, config["order"]||[]
@@ -94,6 +98,14 @@ private
94
98
  end
95
99
  end
96
100
 
101
+ def precompile(config)
102
+ config["precompile"].each do |dest, pattern|
103
+ matches = Dir.glob(pattern).sort_by(&:downcase)
104
+ next if matches.select { |p| cache.miss? p }.empty?
105
+ write_template(dest, matches)
106
+ end
107
+ end
108
+
97
109
  def revision
98
110
  dump_manifest
99
111
  [env.revision].flatten.each do |rev|
@@ -103,11 +115,17 @@ private
103
115
  end
104
116
  end
105
117
 
106
- private
118
+ def write_template(dest, child_assets)
119
+ asset = Asset.new(File.join env.public_folder, dest)
120
+ content = child_assets.inject("") {|s, m| s << cache[m].content}
121
+ asset.content = Wrapper::Template.definition(content)
122
+ asset.compress if compile?
123
+ asset.write
124
+ end
107
125
 
108
126
  def write_asset(dest, child_assets)
109
127
  asset = Asset.new(File.join env.public_folder, dest)
110
- definition = (asset.path == env.definition ? Wrapper.definition : "")
128
+ definition = (asset.path == env.definition ? Wrapper::Module.definition : "")
111
129
  asset.content = child_assets.inject(definition) {|s, m| s << cache[m].content}
112
130
  asset.compress if compile?
113
131
  asset.write
@@ -49,7 +49,11 @@ module Linner
49
49
  end
50
50
 
51
51
  def wrap(source)
52
- Wrapper.wrap(logical_path.chomp(File.extname logical_path), source)
52
+ if javascript?
53
+ Wrapper::Module.wrap(logical_path.chomp(File.extname logical_path), source)
54
+ else
55
+ Wrapper::Template.wrap(logical_path.chomp(File.extname logical_path), source)
56
+ end
53
57
  end
54
58
 
55
59
  def javascript?
@@ -60,8 +64,12 @@ module Linner
60
64
  Tilt[path] and Tilt[path].default_mime_type == "text/css"
61
65
  end
62
66
 
67
+ def template?
68
+ Tilt[path] and Tilt[path].default_mime_type == "text/template"
69
+ end
70
+
63
71
  def wrappable?
64
- !!(self.javascript? and !Linner.env.modules_ignored.include?(@path))
72
+ !!(self.javascript? and !Linner.env.modules_ignored.include?(@path) or self.template?)
65
73
  end
66
74
 
67
75
  def write
@@ -0,0 +1,66 @@
1
+ require "digest"
2
+ require "fileutils"
3
+ require "open-uri"
4
+
5
+ module Linner
6
+ class Bundler
7
+ VENDOR = Pathname(".").expand_path.join "vendor"
8
+ REPOSITORY = File.expand_path "~/.linner/bundles"
9
+
10
+ Bundle = Struct.new(:name, :version, :url) do
11
+ def path
12
+ File.join(REPOSITORY, name, version, File.basename(url))
13
+ end
14
+ end
15
+
16
+ def initialize(bundles)
17
+ @bundles = []
18
+ bundles.each do |name, props|
19
+ @bundles << Bundle.new(name, props["version"], props["url"])
20
+ end
21
+ end
22
+
23
+ def check
24
+ return [false, "Bundles didn't exsit!"] unless File.exists? REPOSITORY
25
+ @bundles.each do |bundle|
26
+ unless File.exists?(bundle.path) and File.exists?(File.join(VENDOR, bundle.name))
27
+ return [false, "Bundle #{bundle.name} v#{bundle.version} didn't match!"]
28
+ end
29
+ end
30
+ return [true, "Perfect bundled, ready to go!"]
31
+ end
32
+
33
+ def install
34
+ unless File.exists? REPOSITORY
35
+ FileUtils.mkdir_p(REPOSITORY)
36
+ end
37
+ @bundles.each do |bundle|
38
+ if bundle.version != "master"
39
+ next if File.exists?(bundle.path) and File.exists?(File.join(VENDOR, bundle.name))
40
+ end
41
+ puts "Installing #{bundle.name} #{bundle.version}..."
42
+ install_to_repository bundle.url, bundle.path
43
+ link_to_vendor bundle.path, File.join(VENDOR, bundle.name)
44
+ end
45
+ end
46
+
47
+ def perform
48
+ check and install
49
+ end
50
+
51
+ private
52
+ def install_to_repository(url, path)
53
+ FileUtils.mkdir_p File.dirname(path)
54
+ File.open(path, "w") do |dist|
55
+ open(url, "r:UTF-8") {|file| dist.write file.read}
56
+ end
57
+ end
58
+
59
+ def link_to_vendor(path, dist)
60
+ if !File.exist?(dist) or Digest::MD5.file(path).hexdigest != Digest::MD5.file(dist).hexdigest
61
+ FileUtils.mkdir_p File.dirname(dist)
62
+ FileUtils.cp path, dist
63
+ end
64
+ end
65
+ end
66
+ end
@@ -15,18 +15,37 @@ module Linner
15
15
  puts Linner::VERSION
16
16
  end
17
17
 
18
+ desc "check", "check dependencies"
19
+ def check
20
+ message = Linner::Bundler.new(env.bundles).check
21
+ puts (message.first ? "🍵 :" : "👻 :") + message.last
22
+ end
23
+
24
+ desc "install", "install dependencies"
25
+ def install
26
+ begin
27
+ Linner::Bundler.new(env.bundles).perform
28
+ rescue
29
+ puts "👻 : Install failed!"
30
+ puts $!
31
+ return
32
+ end
33
+ puts "🍵 : Perfect installed all bundles!"
34
+ end
35
+
18
36
  desc "build", "build assets"
19
37
  def build
20
38
  Linner.compile = true
21
39
  clean
22
- Notifier.profile { Linner.perform }
40
+ perform
23
41
  end
24
42
 
25
43
  desc "watch", "watch assets"
26
44
  def watch
27
45
  trap(:INT) { exit! }
28
46
  clean
29
- perform_proc.call
47
+ Linner::Bundler.new(env.bundles).perform
48
+ perform
30
49
  watch_for_perform
31
50
  watch_for_reload
32
51
  sleep
@@ -48,20 +67,20 @@ module Linner
48
67
  Linner.env
49
68
  end
50
69
 
51
- def perform_proc
52
- @proc ||= Proc.new do
53
- begin
54
- Notifier.profile{ Linner.perform }
55
- rescue
56
- Notifier.error $!
70
+ def perform
71
+ begin
72
+ Notifier.profile do
73
+ Linner.perform
57
74
  end
75
+ rescue
76
+ Notifier.error $!
58
77
  end
59
78
  end
60
79
 
61
80
  def watch_for_perform
62
81
  Listen.to env.watched_paths do |modified, added, removed|
63
82
  Linner.cache.expire_by(modified + added + removed)
64
- perform_proc.call
83
+ perform
65
84
  end
66
85
  end
67
86
 
@@ -5,7 +5,7 @@ module Linner
5
5
  class Compressor
6
6
 
7
7
  def self.compress(asset)
8
- if asset.javascript?
8
+ if asset.javascript? or asset.template?
9
9
  Uglifier.compile asset.content, comments: "none"
10
10
  elsif asset.stylesheet?
11
11
  CSSminify.new.compress asset.content
@@ -31,6 +31,10 @@ module Linner
31
31
  end
32
32
  end
33
33
 
34
+ def bundles
35
+ @env["bundles"] || []
36
+ end
37
+
34
38
  def modules_ignored
35
39
  Dir.glob(@env["modules"]["ignored"])
36
40
  end
@@ -1,6 +1,7 @@
1
1
  require "tilt"
2
2
  require "sass"
3
3
  require "compass"
4
+ require "handlebars.rb"
4
5
  require "coffee_script"
5
6
 
6
7
  module Tilt
@@ -30,8 +31,19 @@ module Tilt
30
31
  end
31
32
  end
32
33
 
34
+ class HandlebarsTemplate < Template
35
+ self.default_mime_type = 'text/template'
36
+
37
+ def prepare; end
38
+
39
+ def evaluate(scope, locals, &block)
40
+ @output ||= Handlebars.precompile(data)
41
+ end
42
+ end
43
+
33
44
  register CSSTemplate, "css"
34
45
  register JavascriptTemplate, "js"
46
+ register HandlebarsTemplate, "hbs", "handlebars"
35
47
 
36
48
  register CompassSassTemplate, "sass"
37
49
  prefer CompassSassTemplate
@@ -1,2 +1,3 @@
1
1
  module.exports = ->
2
+ $("body").append Handlebars.templates["welcome"]()
2
3
  console.info "log from app!"
@@ -0,0 +1 @@
1
+ <p>Hello world! This is Linner Boilerplate.</p>
@@ -13,10 +13,9 @@
13
13
  <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
14
14
  <![endif]-->
15
15
 
16
- <p>Hello world! This is Linner Boilerplate.</p>
17
-
18
16
  <script src="/scripts/vendor.js"></script>
19
17
  <script src="/scripts/app.js"></script>
18
+ <script src="/scripts/templates.js"></script>
20
19
  <script>require("app")()</script>
21
20
  </body>
22
21
  </html>
@@ -17,10 +17,23 @@ groups:
17
17
  "/images/": "app/images/**/*.{png,gif}"
18
18
  views:
19
19
  copy:
20
- "/": "app/views/**/*.{html,hbs}"
20
+ "/": "app/views/**/*.html"
21
+ templates:
22
+ paths:
23
+ - "app/templates"
24
+ precompile:
25
+ "/scripts/templates.js": "app/templates/**/*.hbs"
21
26
  modules:
22
27
  wrapper: "cmd"
23
28
  ignored: "vendor/**/*"
24
29
  definition: "/scripts/app.js"
25
30
  revision: "index.html"
26
31
  notification: true
32
+ bundles:
33
+ "jquery.js":
34
+ version: "1.10.2"
35
+ url: "http://code.jquery.com/jquery-1.10.2.js"
36
+ "handlebars.js":
37
+ version: "1.0.0"
38
+ url: "https://raw.github.com/wycats/handlebars.js/1.0.0/dist/handlebars.runtime.js"
39
+
@@ -0,0 +1 @@
1
+ .gitkeep
@@ -0,0 +1 @@
1
+ .gitkeep
@@ -1,3 +1,3 @@
1
1
  module Linner
2
- VERSION = "0.4.6"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -1,17 +1,32 @@
1
1
  module Linner
2
- class Wrapper
3
- WRAPPER =
4
- 'this.require.define({"%s":' +
5
- 'function(exports, require, module){' +
6
- '%s' +
7
- ";}});\n"
2
+ module Wrapper
3
+ class Module
4
+ def self.wrap(name, content)
5
+ <<-WRAPPER
6
+ this.require.define({"#{name}":function(exports, require, module){#{content};}});
7
+ WRAPPER
8
+ end
8
9
 
9
- def self.wrap(name, content)
10
- WRAPPER % [name, content]
10
+ def self.definition
11
+ File.read(File.join File.dirname(__FILE__), "../../vendor", "require_definition.js")
12
+ end
11
13
  end
12
14
 
13
- def self.definition
14
- File.read(File.join File.dirname(__FILE__), "../../vendor", "require_definition.js")
15
+ class Template
16
+ def self.wrap(name, content)
17
+ <<-WRAPPER
18
+ templates["#{name}"] = template(#{content});
19
+ WRAPPER
20
+ end
21
+
22
+ def self.definition(content)
23
+ <<-DEFINITION
24
+ (function() {
25
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
26
+ #{content}
27
+ })();
28
+ DEFINITION
29
+ end
15
30
  end
16
31
  end
17
32
  end