jing 0.1.5 → 0.1.6

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
  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