linner 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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/README.md +37 -0
- data/Rakefile +1 -0
- data/bin/linner +4 -0
- data/lib/linner.rb +66 -0
- data/lib/linner/asset.rb +46 -0
- data/lib/linner/command.rb +50 -0
- data/lib/linner/compressor.rb +16 -0
- data/lib/linner/environment.rb +29 -0
- data/lib/linner/notifier.rb +23 -0
- data/lib/linner/sort.rb +27 -0
- data/lib/linner/template.rb +25 -0
- data/lib/linner/templates/app/images/.gitkeep +0 -0
- data/lib/linner/templates/app/scripts/app.coffee +2 -0
- data/lib/linner/templates/app/styles/app.sass +0 -0
- data/lib/linner/templates/app/views/index.html +22 -0
- data/lib/linner/templates/bin/server +3 -0
- data/lib/linner/templates/config.yml +26 -0
- data/lib/linner/templates/test/.gitkeep +0 -0
- data/lib/linner/templates/vendor/commonjs.js +60 -0
- data/lib/linner/templates/vendor/jquery-1.10.2.js +9789 -0
- data/lib/linner/version.rb +3 -0
- data/lib/linner/wrapper.rb +17 -0
- data/linner.gemspec +32 -0
- metadata +211 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c41ee9a6cf2562f365e6e9a263adb9e2b8568dbb
|
4
|
+
data.tar.gz: 93028ef33bbaee5194089522c5c95378a9f15bd1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 81973fdb6415ffb48402bbe9399281dcc9cac652ee0210d9a9b9cd5b5f4d613112d1ae5e5008df95d260e2180cd74ab087ddc51c61bd3596d3d2a821d80a3e6a
|
7
|
+
data.tar.gz: 0bdd137d04e3f169271e6721ccb56ceabb7145d1ca14460a0b7ea42572ab81591dc0d63e6f20f5613fa7628ca939076bd4fd8fe32f753d1e919203a30132e882
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Linner
|
2
|
+
|
3
|
+
HTML5 Application Assembler
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install linner
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
Skeleton:
|
12
|
+
|
13
|
+
$ linner new webapp && cd webapp
|
14
|
+
|
15
|
+
Watch:
|
16
|
+
|
17
|
+
$ linner watch
|
18
|
+
|
19
|
+
Server:
|
20
|
+
|
21
|
+
$ ./bin/server # or server if put "./bin" in your PATH
|
22
|
+
|
23
|
+
Build:
|
24
|
+
|
25
|
+
$ linner build
|
26
|
+
|
27
|
+
Clean:
|
28
|
+
|
29
|
+
$ linner clean
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
|
33
|
+
1. Fork it
|
34
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
35
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
36
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
37
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/linner
ADDED
data/lib/linner.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require "linner/version"
|
2
|
+
require "linner/command"
|
3
|
+
require "linner/asset"
|
4
|
+
require "linner/sort"
|
5
|
+
require "linner/environment"
|
6
|
+
require "linner/wrapper"
|
7
|
+
require "linner/template"
|
8
|
+
require "linner/notifier"
|
9
|
+
require "linner/compressor"
|
10
|
+
|
11
|
+
module Linner
|
12
|
+
extend self
|
13
|
+
|
14
|
+
def root
|
15
|
+
@root ||= Pathname('.').expand_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def environment
|
19
|
+
@env ||= Linner::Environment.new root.join("config.yml")
|
20
|
+
end
|
21
|
+
|
22
|
+
def perform(options = {})
|
23
|
+
compile = options[:compile]
|
24
|
+
environment.files.values.each do |config|
|
25
|
+
Thread.new {concat(config).each {|asset| asset.compress if compile; asset.write}}.join
|
26
|
+
Thread.new {copy(config)}.join
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def concat(config)
|
32
|
+
assets = []
|
33
|
+
concat, before, after = environment.extract_by(config)
|
34
|
+
concat.each do |dist, regex|
|
35
|
+
Thread.new do
|
36
|
+
dist = Linner::Asset.new(environment.public_folder.join(dist).to_path)
|
37
|
+
matches = Dir.glob(File.join root, regex).uniq
|
38
|
+
matches.extend(Linner::Sort)
|
39
|
+
matches.sort(before: before, after: after).each do |m|
|
40
|
+
asset = Linner::Asset.new(m)
|
41
|
+
content = asset.content
|
42
|
+
if asset.wrappable?
|
43
|
+
content = asset.wrap
|
44
|
+
end
|
45
|
+
dist.content << content
|
46
|
+
end
|
47
|
+
assets << dist
|
48
|
+
end.join
|
49
|
+
end
|
50
|
+
assets
|
51
|
+
end
|
52
|
+
|
53
|
+
def copy(config)
|
54
|
+
config["copy"].to_h.each do |dist, regex|
|
55
|
+
Thread.new do
|
56
|
+
matches = Dir.glob(File.join root, regex)
|
57
|
+
matches.each do |path|
|
58
|
+
asset = Linner::Asset.new(path)
|
59
|
+
asset.path = File.join(environment.public_folder, dist, asset.logical_path)
|
60
|
+
next if File.exist? asset.path and FileUtils.uptodate? path, [asset.path]
|
61
|
+
asset.write
|
62
|
+
end
|
63
|
+
end.join
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/linner/asset.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Linner
|
2
|
+
class Asset
|
3
|
+
|
4
|
+
attr_accessor :path, :content
|
5
|
+
|
6
|
+
def initialize(path)
|
7
|
+
@path = path
|
8
|
+
if path =~ /#{Linner.root.to_path}\/public/
|
9
|
+
@content = ""
|
10
|
+
else
|
11
|
+
@content = Linner::Template.new(path).render
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def type
|
16
|
+
@type ||= if @path =~ /\.(js|coffee)$/
|
17
|
+
"script"
|
18
|
+
elsif @path =~ /\.(css|sass|scss)/
|
19
|
+
"style"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def wrap
|
24
|
+
Linner::Wrapper.wrap(logical_path.chomp(File.extname logical_path), @content)
|
25
|
+
end
|
26
|
+
|
27
|
+
def wrappable?
|
28
|
+
!!(!@path.include? Linner.root.join("vendor").to_path and type == "script")
|
29
|
+
end
|
30
|
+
|
31
|
+
def write
|
32
|
+
FileUtils.mkdir_p File.dirname(@path)
|
33
|
+
File.open @path, "w+" do |file|
|
34
|
+
file.write @content
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def compress
|
39
|
+
@content = Linner::Compressor.compress(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def logical_path
|
43
|
+
@logical_path ||= @path.gsub(/#{Linner.root}\/app\/\w*\//, "")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "listen"
|
3
|
+
|
4
|
+
module Linner
|
5
|
+
class Command < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.dirname(__FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "build", "build assets"
|
13
|
+
def build
|
14
|
+
Linner::Notifier.info do
|
15
|
+
Linner.perform compile: true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "watch", "watch assets"
|
20
|
+
def watch
|
21
|
+
proc = Proc.new do |modified, added, removed|
|
22
|
+
begin
|
23
|
+
Linner::Notifier.info{ Linner.perform }
|
24
|
+
rescue
|
25
|
+
Linner::Notifier.error $!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
proc.call
|
29
|
+
listener = Listen.to "app/", "vendor/", "test/", filter: /\.(js|coffee|css|sass|scss)$/
|
30
|
+
listener.change &proc
|
31
|
+
trap :INT do
|
32
|
+
Linner::Notifier.exit
|
33
|
+
exit!
|
34
|
+
end
|
35
|
+
listener.start!
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "clean", "clean assets"
|
39
|
+
def clean
|
40
|
+
FileUtils.rm_rf File.join(Linner.environment.public_folder, "/.")
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "new", "create the skeleton of project"
|
44
|
+
def new(name)
|
45
|
+
directory('templates', name)
|
46
|
+
chmod("#{name}/bin/server", 0755)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "uglifier"
|
2
|
+
require "yui/compressor"
|
3
|
+
|
4
|
+
module Linner
|
5
|
+
class Compressor
|
6
|
+
|
7
|
+
def self.compress(asset)
|
8
|
+
case asset.type
|
9
|
+
when "script"
|
10
|
+
Uglifier.compile asset.content, comments: "none"
|
11
|
+
when "style"
|
12
|
+
YUI::CssCompressor.new.compress asset.content
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module Linner
|
4
|
+
class Environment
|
5
|
+
|
6
|
+
def initialize(path)
|
7
|
+
@config ||= YAML::load File.read path
|
8
|
+
end
|
9
|
+
|
10
|
+
def public_folder
|
11
|
+
Linner.root.join(@config["paths"].to_h["public"] || "public")
|
12
|
+
end
|
13
|
+
|
14
|
+
def files
|
15
|
+
@config["files"] || []
|
16
|
+
end
|
17
|
+
|
18
|
+
def notifications
|
19
|
+
@config["notifications"] || false
|
20
|
+
end
|
21
|
+
|
22
|
+
def extract_by(file)
|
23
|
+
concat = file["concat"] || []
|
24
|
+
before = file["order"].to_h["before"] || []
|
25
|
+
after = file["order"].to_h["after"] || []
|
26
|
+
[concat, before, after]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "terminal-notifier"
|
2
|
+
|
3
|
+
module Linner
|
4
|
+
class Notifier
|
5
|
+
|
6
|
+
def self.info
|
7
|
+
time = Time.now
|
8
|
+
yield
|
9
|
+
puts "š : Done in #{'%.3f' % (Time.now - time)}s."
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.error(message)
|
13
|
+
puts message = "š» : #{message}!"
|
14
|
+
if Linner.environment.notifications && TerminalNotifier.available?
|
15
|
+
TerminalNotifier.notify message, :title => 'Linner'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.exit
|
20
|
+
puts "\ršµ : Let's take a break!"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/linner/sort.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Linner
|
2
|
+
module Sort
|
3
|
+
|
4
|
+
def sort(before: [], after: [])
|
5
|
+
sort_by_before(self, before)
|
6
|
+
sort_by_after(self, after)
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
def sort_by_before(list, before)
|
12
|
+
before.reverse.each do |f|
|
13
|
+
if i = list.index {|x| x =~ /#{f}/i}
|
14
|
+
list.unshift list.delete_at i
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def sort_by_after(list, after)
|
20
|
+
after.reverse.each do |f|
|
21
|
+
if i = list.index {|x| x =~ /#{f}/i}
|
22
|
+
list.push list.delete_at i
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
require 'sass'
|
3
|
+
require 'coffee_script'
|
4
|
+
|
5
|
+
module Linner
|
6
|
+
class Template
|
7
|
+
|
8
|
+
def initialize(path)
|
9
|
+
@path = path
|
10
|
+
end
|
11
|
+
|
12
|
+
def render
|
13
|
+
if supported_template? @path
|
14
|
+
Tilt.new(@path).render
|
15
|
+
else
|
16
|
+
File.read @path
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def supported_template?(path)
|
22
|
+
%w[.coffee .sass .scss].include? File.extname(path)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<head>
|
3
|
+
<meta charset="utf-8">
|
4
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
5
|
+
<title>Linner boilerplate</title>
|
6
|
+
<meta name="description" content="">
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
8
|
+
|
9
|
+
<link rel="stylesheet" href="styles/app.css">
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
<!--[if lt IE 7]>
|
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
|
+
<![endif]-->
|
15
|
+
|
16
|
+
<p>Hello world! This is Linner Boilerplate.</p>
|
17
|
+
|
18
|
+
<script src="scripts/vendor.js"></script>
|
19
|
+
<script src="scripts/app.js"></script>
|
20
|
+
<script>require("app")()</script>
|
21
|
+
</body>
|
22
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
paths:
|
2
|
+
public: "public"
|
3
|
+
files:
|
4
|
+
scripts:
|
5
|
+
concat:
|
6
|
+
"scripts/app.js": "app/scripts/**/*.{js,coffee}"
|
7
|
+
"scripts/vendor.js": "vendor/**/*.{js,coffee}"
|
8
|
+
order:
|
9
|
+
before:
|
10
|
+
- "vendor/jquery-1.10.2.js"
|
11
|
+
after:
|
12
|
+
- "vendor/commonjs.js"
|
13
|
+
styles:
|
14
|
+
concat:
|
15
|
+
"styles/app.css": "app/styles/**/[a-z]*.{css,scss,sass}"
|
16
|
+
images:
|
17
|
+
copy:
|
18
|
+
"images/": "app/images/**/*.{png,gif}"
|
19
|
+
views:
|
20
|
+
copy:
|
21
|
+
"/": "app/views/**/*.{html,hbs}"
|
22
|
+
modules:
|
23
|
+
wrapper: "cmd"
|
24
|
+
conventions:
|
25
|
+
ignored: "_"
|
26
|
+
notifications: true
|