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 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
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .sass-cache
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in linner.gemspec
4
+ gemspec
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
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + "/../lib/linner"
4
+ Linner::Command.start
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
@@ -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
@@ -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
@@ -0,0 +1,2 @@
1
+ module.exports = ->
2
+ console.info "log from app!"
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,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ ruby -run -e httpd "./public" -p 3000
@@ -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