jing 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40b0c3e50b02a0213e97bd9b1a7fd5f4e8b8efce03faad1e4943906bc300c186
4
- data.tar.gz: 2ad0975e17e68f10b3187f38dab7321f98c23adac21e7e9b477149325c0c8f2f
3
+ metadata.gz: 44ebf6b1808776a35ea1a2e98e7ec1738c2be1735ef7c9143c6e3f50a61668cf
4
+ data.tar.gz: '09fbb03a85e717c4211961e7f6cc247d8ac88bf5bb5c43fa56bbfa770526a33b'
5
5
  SHA512:
6
- metadata.gz: 0dc11fe05f38be3035d01941b3aea6ea8f0a4dfe978711dbfad8421ddecb0bfd0e54a3be57ba5ea5b38461d9670eb32f0983674113e13111ff8a4677aa53bfb0
7
- data.tar.gz: 3ce97d022d737b8b781ee95a916dd5d72b2d0390410fe5e43c165b44567f466e5ff320de2e9a4d717b2a7719c66d13230c9fec8bfb70291b63888949ed7a188b
6
+ metadata.gz: 40f13f6dfae9ff73d0c448559fd11dbef242ee545d31015cbabacc48528ee8bde845ee7d87b3a26b160d4d5c09cd653e081a8759aca58cb9f38dc16785ff632b
7
+ data.tar.gz: cbdf1e238a9f58035826d92981676dbeb906b632a543a4597519c2796ee25e701d706bc3baede9ca3954869f2f09fe9b03719b4fd482eee92f1678a5758ce24b
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jing (0.1.3)
4
+ jing (0.1.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -29,23 +29,36 @@ Or install it yourself as:
29
29
 
30
30
  call `jing` on the command line or have a look at the code (it's tiny) :)
31
31
 
32
-
33
- Creates a new folder `mypage` with a basic setup:
32
+ Creates a new folder `mypage` or updates an existing one and adds a basic setup:
34
33
 
35
34
  $ jing create mypage
36
35
  $ cd mypage
37
-
36
+
38
37
  Build the current project:
39
-
38
+
40
39
  $ jing build
41
-
40
+
42
41
  Automatically build the page whenever a file in the project folder changes:
43
42
 
44
43
  $ jing watch
45
-
46
- Serves the current project folder on `http://0.0.0.0:8000`:
47
-
44
+ $ jing watch -full_build true # to not skip uglifying js files (slower)
45
+
46
+ Serves the current projects _dst folder on `http://0.0.0.0:8000`:
47
+
48
48
  $ jing serve
49
+ $ jing serve -no_auto_reload true # to not inject auto page reload code into html files
50
+ $ jing serve -port 1234 -root somepath # to change port and root directory
51
+
52
+ Options that work in all commands:
53
+ -src somepath # changes the source folder - default: ./ (current folder)
54
+ -dst somepath # changes the output folder - default: ./_dst
55
+ -layouts folder # changes the layouts folder - default: ./_layouts
56
+ -partials folder # changes the partials folder - default: ./_partials
57
+
58
+
59
+ Show current version
60
+
61
+ $ jing version
49
62
 
50
63
  File endings work like Russian dolls: They get converted from outer to inner. Rails folks should be somewhat familiar with that but here it's a bit stricter.
51
64
 
@@ -55,6 +68,8 @@ Folders starting with `_` have special meaning, they generally won't get copied
55
68
 
56
69
  `_layouts` holds layouts (TODO: explanation)
57
70
 
71
+ `_dst' holds the generated site
72
+
58
73
  `.meta.yml` holds global meta variables available in templates when not overwritten
59
74
 
60
75
  ~~I'll try and add a basic example project soon.~~ Check out the examples folder. If you feel like giving this a try and have questions feel free to open an issue or reach out otherwise. Pull requests welcome too.
@@ -63,7 +78,7 @@ Folders starting with `_` have special meaning, they generally won't get copied
63
78
 
64
79
  Extending is fairly easy.
65
80
 
66
- `@converters` variable in the initialize method holds a bunch of converters. Just add one in the spirit of the others. You can also do this on the fly when initiating the Jing Class by passing the `converter_addons` option.
81
+ `@converters` variable in the initialize method holds a bunch of converters. Just add one in the spirit of the others.
67
82
 
68
83
  Class methods that end in a bang `!` automatically are registered as cli commands. If you wish to add a command just add a bang-method and you should be done.
69
84
 
@@ -1,8 +1,29 @@
1
- require "jing/version"
1
+ %w[jing/version erb yaml fileutils time webrick bundler/inline].each { |e| require e }
2
+ gemfile { source('https://rubygems.org')
3
+ %w[filewatcher sassc typescript-node uglifier kramdown].each { |e| gem e }
4
+ }
2
5
 
3
- %w[erb yaml fileutils time webrick ostruct bundler/inline].each { |e| require e }
6
+ module SymbolizeHelper
7
+ extend self
8
+ def symbolize_recursive(hash)
9
+ {}.tap{ |h| hash.each { |key, value| h[key.to_sym] = transform(value) } }
10
+ end
11
+ private
12
+ def transform(thing)
13
+ return symbolize_recursive(thing) if thing.is_a?(Hash)
14
+ return thing.map { |v| transform(v) } if thing.is_a?(Array)
15
+ thing
16
+ end
17
+ refine Hash do
18
+ def deep_symbolize_keys
19
+ SymbolizeHelper.symbolize_recursive(self)
20
+ end
21
+ end
22
+ end
4
23
 
5
24
  module Jing
25
+ using SymbolizeHelper
26
+
6
27
  class Jing
7
28
  attr_accessor :converters, :converter_extensions
8
29
 
@@ -11,44 +32,36 @@ module Jing
11
32
  @dst = File.expand_path(opts[:dst] || File.join(@src, '_dst'))
12
33
  @layouts = opts[:layouts] || '_layouts'
13
34
  @partials = opts[:partials] || '_partials'
14
- @loaded_gems = {}
15
- @converters = (opts[:converter_addons] || []) + [
16
- {extensions: %w[erb], handler: Proc.new { |body, meta, ctx|
17
- ERB.new(body).result(OpenStruct.new(meta: meta).instance_eval { ctx })
18
- }},
19
- {extensions: %w[html htm], handler: Proc.new { |body, meta, ctx|
35
+ @converters = {
36
+ %w[erb] => ->(body, meta, ctx){
37
+ ctx.local_variable_set(:meta, meta)
38
+ ERB.new(body).result(ctx)
39
+ },
40
+ %w[html htm] => ->(body, meta, ctx){
41
+ ctx.local_variable_set(:meta, meta)
20
42
  if meta[:layout] && layout = Dir[File.join(@src, @layouts, "#{meta[:layout]}.*")].first
21
- content = load_content(layout, meta)
22
- ERB.new(content[:body]).result(OpenStruct.new(meta: meta, body: body).instance_eval { ctx })
43
+ ctx.local_variable_set(:body, body)
44
+ ERB.new(load_content(layout, meta)[:body]).result(ctx)
23
45
  else
24
- ERB.new(body).result(OpenStruct.new(meta: meta).instance_eval { ctx })
46
+ ERB.new(body).result(ctx)
25
47
  end
26
- }},
27
- {extensions: %w[scss sass css], handler: ->(body, meta, ctx){
28
- load_gem 'sassc'
48
+ },
49
+ %w[scss sass css] => ->(body, meta, ctx){
29
50
  SassC::Engine.new(body, style: (meta[:style] || :compressed)).render
30
- }},
31
- {extensions: %w[ts], handler: ->(body, meta, ctx){
32
- load_gem 'typescript-node'
51
+ },
52
+ %w[ts] =>->(body, meta, ctx){
33
53
  TypeScript::Node.compile(body, '--target', (meta[:style] || 'ES5'))
34
- }},
35
- {extensions: %w[js], handler: ->(body, meta, ctx){
36
- load_gem 'uglifier'
54
+ },
55
+ %w[js] => ->(body, meta, ctx){
37
56
  Uglifier.compile(body, harmony: true, compress: false, mangle: false, output: {ascii_only: true})
38
- }},
39
- {extensions: %w[md markdown], handler: ->(body, meta, ctx){
40
- load_gem 'kramdown'
57
+ },
58
+ %w[md markdown] => ->(body, meta, ctx){
41
59
  Kramdown::Document.new(body).to_html
42
- }},
43
- ]
60
+ }
61
+ }
44
62
 
45
- @converter_extensions = @converters.map { |e| e[:extensions] }.flatten
46
- main_meta_file = File.join(@src, '.meta.yml')
47
- @meta = YAML.load(File.read(main_meta_file)).map { |k,v| [k.to_sym,v] }.to_h if File.exist?(main_meta_file)
48
- end
49
-
50
- def load_gem(name, opts={})
51
- @loaded_gems[name] ||= gemfile { source(opts.delete(:source)||'https://rubygems.org'); gem(name, opts) }
63
+ @converter_extensions = @converters.keys.flatten
64
+ File.join(@src, '.meta.yml').tap{|e| @meta = File.exist?(e) ? YAML.load(File.read(e)).deep_symbolize_keys : {}}
52
65
  end
53
66
 
54
67
  def active_exts(file)
@@ -62,15 +75,15 @@ module Jing
62
75
  end
63
76
 
64
77
  def load_content(file, meta={})
65
- body = File.open(file, 'rb').read
66
- return {body: body, meta: meta} unless @converter_extensions.include?(File.extname(file)[1..-1])
78
+ body = File.open(file, 'rb'){|f|f.read}
79
+ return {body: body, meta: meta.deep_symbolize_keys} unless @converter_extensions.include?(File.extname(file)[1..-1])
67
80
  body.match(/^(?:(---\s*\n.*?\n?)^(?:---\s*$\n?))?(.*)$/m)
68
81
  meta.merge!(YAML.load($1).map { |k,v| [k.to_sym,v] }.to_h) if $1
69
- {body: $2, meta: meta}
82
+ {body: $2, meta: meta.deep_symbolize_keys}
70
83
  end
71
84
 
72
85
  def render(file, meta={})
73
- if !File.file?(file)
86
+ unless File.file?(file)
74
87
  file = Dir[File.join(@src, @partials, "#{file}.*")].first
75
88
  else
76
89
  meta.merge!(file: file)
@@ -80,19 +93,19 @@ module Jing
80
93
  body = content[:body]
81
94
  exts = active_exts(file)
82
95
  exts.each do |ext|
83
- converter = @converters.find { |c| c[:extensions].include?(ext) }
84
- body = converter ? converter[:handler].call(body, content[:meta], binding) : body
96
+ converter = @converters[@converters.keys.find { |k| k.include?(ext) }]
97
+ body = converter ? converter.call(body, content[:meta], binding) : body
85
98
  end
86
- puts "#{'%.4fs' % (Time.now-t)}\t#{file[@src.size+1..-1]} >#{exts.join('>')}> #{dstname(file, @dst)[@dst.size+1..-1]} (#{(body.size/1024.0).round(2)}kb)"
99
+ puts "#{'%.4fs' % (Time.now-t)}\t#{file[@src.size+1..-1]} >#{exts.join('>')}> #{dstname(file, @dst)[@dst.size+1..-1]} (#{ '%.2fkb' % (body.size/1024.0)})"
87
100
  body
88
101
  rescue => e
89
102
  puts "Error\t#{file[@src.size+1..-1]}\n\t#{e.message}\n#{e.backtrace.map{|x| "\t#{x}"}.join("\n")}"
90
103
  end
91
104
 
92
105
  def build!(opts={})
93
- t = Time.now
94
- FileUtils.rm_r(@dst) if File.exist?(@dst)
95
- Dir.mkdir(@dst)
106
+ t,s = Time.now, 0
107
+ FileUtils.rm_rf("#{@dst}/.", secure: true)
108
+ Dir.mkdir(@dst) unless File.exist?(@dst)
96
109
  Dir[File.join(@src, '**', '*')].each do |file|
97
110
  next unless File.file?(file)
98
111
  dir = File.dirname(file)[@src.size+1..-1]
@@ -100,18 +113,16 @@ module Jing
100
113
  outfile = dstname(file, File.join(*[@dst, dir].compact))
101
114
  out = render(file, @meta.merge(layout: dir))
102
115
  FileUtils.mkdir_p(File.dirname(outfile))
103
- File.open(outfile, 'wb').write(out)
116
+ File.open(outfile, 'wb'){|f|s+=f.write(out)}
104
117
  end
105
- puts "#{'%.4fs' % (Time.now-t)} total"
118
+ puts "#{'%.4fs' % (Time.now-t)}, #{'%.2fkb' % (s/1024.0)} total"
106
119
  end
107
120
 
108
121
  def watch!(opts={})
109
- @converters.delete_if{|e| e[:extensions]==['js']}
110
- @converters<<{extensions: %w[js], handler: ->(body, meta, ctx){body}}
122
+ @converters[%w[js]] = ->(body, meta, ctx){puts 'skipping uglyfier'; body} unless opts[:full_build]
111
123
  build!(opts)
112
- load_gem('filewatcher')
113
124
  Filewatcher.new([@src, '**', '*']).watch do |filename, event|
114
- unless File.expand_path(filename) == @dst
125
+ unless filename.start_with?(@dst)
115
126
  puts "\nWATCHED: #{filename}\t#{event}\t#{Time.now}"
116
127
  build!(opts)
117
128
  end
@@ -119,13 +130,39 @@ module Jing
119
130
  end
120
131
 
121
132
  def serve!(opts={})
122
- WEBrick::HTTPServer.new(Port: opts[:port] || 8000, DocumentRoot: opts[:root] || @dst).start
133
+ api_route = opts[:api_route] || '/_J_I_N_G_'
134
+ inter = opts[:interval] || 2000
135
+ script = "<script>((t)=>{setInterval(()=>{fetch('#{api_route}').then(r=>r.json()).then((j)=>{if(Date.parse(j.modified)>t){fetch(document.location.pathname).then((r)=>{if(r.ok)window.location.reload(true)})}})}, #{inter})})(new Date().getTime())</script>"
136
+ srv = WEBrick::HTTPServer.new(Port: opts[:port] || 8000, DocumentRoot: opts[:root] || @dst)
137
+
138
+ srv.mount_proc('/') do |rq, rs|
139
+ path = File.join(@dst, rq.path == '/' ? '/index.html' : rq.path)
140
+ raise WEBrick::HTTPStatus::NotFound, "`#{rq.path}' not found." unless File.exist?(path)
141
+ st = File::stat(path)
142
+ rs['etag'] = sprintf("%x-%x-%x", st.ino, st.size, st.mtime.to_i)
143
+ rs['content-type'] = WEBrick::HTTPUtils::mime_type(path, WEBrick::HTTPUtils::DefaultMimeTypes)
144
+ rs['last-modified'] = st.mtime.httpdate
145
+ if rs['content-type'] == 'text/html'
146
+ rs.body = File.open(path, "rb").read.gsub(/(<\/body>)/im){"\n#{script}\n#{$1}"}
147
+ rs['content-length'] = rs.body.size.to_s
148
+ else
149
+ rs['content-length'] = st.size.to_s
150
+ rs.body = File.open(path, "rb")
151
+ end
152
+ end unless opts[:no_auto_reload]
153
+
154
+ srv.mount_proc(api_route) do |req, res|
155
+ res['Content-Type'] = 'application/json'
156
+ res.body = {modified: File.stat(@dst).ctime.iso8601}.to_json
157
+ end
158
+ trap('INT'){ srv.stop }
159
+ srv.start
123
160
  end
124
161
 
125
162
  def create!(opts={})
126
163
  abort("usage: #{File.basename($0)} create -name <pathname>") unless opts[:name]
127
164
  [@layouts, @partials].each { |e| FileUtils.mkdir_p(File.join(opts[:name], e)) }
128
- File.write(File.join(opts[:name], '.meta.yml'), "---\ngenerator: jing #{VERSION}\nname: #{File.basename(opts[:name])}\n---\n")
165
+ File.write(File.join(opts[:name], '.meta.yml'), "---\ngenerator: jing\nname: #{File.basename(opts[:name])}\n---\n")
129
166
  end
130
167
 
131
168
  def version!(opts={})
@@ -1,3 +1,3 @@
1
1
  module Jing
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - pachacamac
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-07 00:00:00.000000000 Z
11
+ date: 2019-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler