wunderbar 1.3.0 → 1.4.0

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: a7f6f11a34c8540709e572a829025fd0d28e8522d9882d336e842caafe91c9f2
4
- data.tar.gz: 57a8d1338c347dacc8beea0ffbf5de77181f88cb5f472ce6078a4e18ae14a08c
3
+ metadata.gz: 01faf4f44e9f567cf1ab080f8f4a54879c0eb6b5d07e0ad6d265ede2cbd4b86f
4
+ data.tar.gz: a0db8a63944a68305a337a1eb5cef8114f5f88034e7a9c451cd37228ad97bc40
5
5
  SHA512:
6
- metadata.gz: 59c38775e59733f8255c29f251cdd6770084517913c0b10fceb3eb809301ddf4487ba01c6b831109fd5d516fdb816ef3ba64729da86b1a0c29d3f5f3e1cd9d82
7
- data.tar.gz: b0b57ca9a258115bb3eb1edb4aaf2df2eee16cbb0229e20f497f70734741e116c21fc045a55fe6bc9e1b04f8f87acd29625f50c061dcdf30840b889435ffdce9
6
+ metadata.gz: d104318bd2e0e2ee9cd721c3b49790ede15b4459dbe253bc58b9108b6fc91fcb077e932a399b9194417a5dc31c62500684db424db534b4b72c1c709e2defedc1
7
+ data.tar.gz: e2d9ca6b2bec1fdb12a253e1ca9df2f73296388c60ee2b165c63305216a353fc0fe37e3ede10c48b6524b7391e060230ca53fa8f393b4d24b957f225da3363a2
data/README.md CHANGED
@@ -366,26 +366,7 @@ Secure by default
366
366
 
367
367
  Wunderbar will properly escape all HTML and JSON output, eliminating problems
368
368
  of HTML or JavaScript injection. This includes calls to `_` to insert text
369
- directly. Unless `nokogiri` was previously required (see [optional
370
- dependencies](#optional-dependencies) below), calls to insert markup
371
- (`_{...}`) will escape the markup if the input is `tainted` and not explicitly
372
- marked as `html-safe?` (when using Rails).
373
-
374
- For Ruby version < 2.6.0:
375
-
376
- > For all environments other than Rails, unless you call `Wunderbar.unsafe!` at
377
- > the top of your script, Wunderbar will also set
378
- > [`$SAFE=1`](http://www.ruby-doc.org/docs/ProgrammingRuby/html/taint.html)
379
- > before processing requests. This means that you will need to
380
- > [`untaint`](ruby-doc.org/core/Object.html#method-i-untaint) all inputs
381
- > received from external sources before you make system calls or access the file
382
- > system.
383
-
384
- A special feature that effectively is only available in the Rails environment:
385
- if the first argument to call that creates an element is `html_safe?`, then
386
- that argument will be treated as a markup instead of as text. This allows one
387
- to make calls like `_td link_to...` without placing the call to `link_to` in a
388
- block.
369
+ directly.
389
370
 
390
371
  Globals provided
391
372
  ---
@@ -454,7 +435,6 @@ The following gems, if installed, will produce cleaner and prettier output:
454
435
  * `nokogumbo` also cleans up HTML fragments inserted via `<<` and `_{}`. If
455
436
  this gem is available, it will be preferred over direct usage of `nokogiri`.
456
437
  * `escape` prettier quoting of `system` commands
457
- * `sanitize` will remove unsafe markup from tainted input
458
438
 
459
439
  Related efforts
460
440
  ---
@@ -30,14 +30,14 @@ module Wunderbar
30
30
  return @path if @path or @contents
31
31
 
32
32
  if @options[:name]
33
- source = (@options[:file] || __FILE__).untaint
33
+ source = @options[:file] || __FILE__
34
34
  @mtime = File.mtime(source)
35
35
  @path = @options[:name]
36
36
 
37
37
  # look for asset in site
38
38
  if ENV['DOCUMENT_ROOT']
39
- root = File.join(ENV['DOCUMENT_ROOT'], 'assets').untaint
40
- dest = File.expand_path(@path, root).untaint
39
+ root = File.join(ENV['DOCUMENT_ROOT'], 'assets')
40
+ dest = File.expand_path(@path, root)
41
41
  if File.exist?(dest) and File.size(dest) == File.size(source)
42
42
  @path = "/assets/#{@path}"
43
43
  return @path
@@ -45,7 +45,7 @@ module Wunderbar
45
45
  end
46
46
 
47
47
  # look for asset in app
48
- dest = File.expand_path(@path, Asset.root).untaint
48
+ dest = File.expand_path(@path, Asset.root)
49
49
  if File.exist?(dest) and File.size(dest) == File.size(source)
50
50
  return @path
51
51
  end
@@ -103,7 +103,7 @@ module Wunderbar
103
103
  @path = '../' * env['PATH_INFO'].to_s.count('/') + 'assets'
104
104
  @root ||= nil
105
105
  @root = File.dirname(env['SCRIPT_FILENAME']) if env['SCRIPT_FILENAME']
106
- @root = File.expand_path((@root || Dir.pwd) + "/assets").untaint
106
+ @root = File.expand_path((@root || Dir.pwd) + "/assets")
107
107
 
108
108
  # Options: typically :name plus either :file or :contents
109
109
  # :name => name to be used for the asset
@@ -51,14 +51,14 @@ module Wunderbar
51
51
  secret = command - flat
52
52
  begin
53
53
  # if available, use escape as it does prettier quoting
54
- raise LoadError if $SAFE > 0 and not defined? Escape
54
+ raise LoadError if not defined? Escape
55
55
  require 'escape'
56
56
  echo = Escape.shell_command(command.compact - secret)
57
57
  rescue LoadError
58
58
  # std-lib function that gets the job done
59
59
  echo = Shellwords.join(command.compact - secret)
60
60
  end
61
- command = flat.compact.map(&:dup).map(&:untaint)
61
+ command = flat.compact
62
62
  else
63
63
  echo = command
64
64
  command = [command]
@@ -461,8 +461,14 @@ module Wunderbar
461
461
  output_prefix = opts[:prefix] || {}
462
462
  output_prefix[:stdin] ||= '$ '
463
463
 
464
- super do |kind, line|
465
- @_target.puts "#{output_prefix[kind]}#{line}"
464
+ if Hash === args.last # support original code which needed two hashes
465
+ super do |kind, line|
466
+ @_target.puts "#{output_prefix[kind]}#{line}"
467
+ end
468
+ else
469
+ super(*args, opts) do |kind, line|
470
+ @_target.puts "#{output_prefix[kind]}#{line}"
471
+ end
466
472
  end
467
473
  end
468
474
 
@@ -587,8 +593,14 @@ module Wunderbar
587
593
  @_target[transcript] = []
588
594
  end
589
595
 
590
- super do |kind, line|
591
- @_target[transcript] << "#{output_prefix[kind]}#{line}"
596
+ if Hash === args.last # support original code which needed two hashes
597
+ super do |kind, line|
598
+ @_target[transcript] << "#{output_prefix[kind]}#{line}"
599
+ end
600
+ else
601
+ super(*args, opts) do |kind, line|
602
+ @_target[transcript] << "#{output_prefix[kind]}#{line}"
603
+ end
592
604
  end
593
605
  end
594
606
 
@@ -120,7 +120,7 @@ module Wunderbar
120
120
  # asset support for Rack
121
121
  request = (scope.respond_to? :request) ? scope.request : nil
122
122
  if request and request.path =~ %r{/assets/\w[-.\w]+}
123
- path = ('.' + scope.request.path).untaint
123
+ path = '.' + scope.request.path
124
124
  headers = {'type' => 'text/plain'}
125
125
  headers['type'] = 'application/javascript' if path =~ /\.js$/
126
126
  out?(scope, headers) { File.read path if File.exist? path }
@@ -2,15 +2,6 @@ require 'wunderbar'
2
2
  require 'coderay'
3
3
  require 'nokogiri'
4
4
 
5
- # workaround for https://github.com/rubychan/coderay/pull/159
6
- module CodeRay::PluginHost
7
- alias_method :old_plugin_path, :plugin_path
8
- def plugin_path *args
9
- args.first.untaint if args.first == CodeRay::CODERAY_PATH
10
- old_plugin_path(*args)
11
- end
12
- end
13
-
14
5
  module Wunderbar
15
6
  class HtmlMarkup
16
7
  def _coderay(*args)
@@ -5,40 +5,6 @@ module Wunderbar
5
5
  TEXT = ARGV.delete('--text')
6
6
  end
7
7
 
8
- # Ruby 2.6.0 gets rid of $SAFE > 1; unfortunately in the process it
9
- # treats $SAFE = 1 as a higher level; @FAFE = 1 no longer is limited
10
- # to taintness checks, it not treats all File operations as unsafe
11
- @@unsafe = (RUBY_VERSION.split('.').map(&:to_i) <=> [2, 6, 0]) == 1
12
-
13
- def self.unsafe!(mode=true)
14
- @@unsafe=mode
15
- end
16
-
17
- def self.safe?
18
- if $SAFE == 0 and not @@unsafe
19
- # some gems (e.g. em-websocket-0.3.6) insert unsafe entries into the
20
- # path, and that prevents requires from succeeding. If it looks like
21
- # we are about to make a transition to $SAFE=1, clean up that mess
22
- # before proceeding.
23
- #
24
- # the goal of $SAFE is not to protect us against software which was
25
- # installed by the owner of the site, but from injection attacks
26
- # contained within data provided by users of the site.
27
- $:.each_with_index do |path, index|
28
- if path.tainted?
29
- $:[index] = File.expand_path(path.dup.untaint).untaint
30
- end
31
- end
32
-
33
- # avoid: "Insecure PATH - (SecurityError)" when using Bundler
34
- if defined? Bundler
35
- ENV['PATH'] = ENV['PATH'].dup.untaint
36
- end
37
- end
38
-
39
- not @@unsafe
40
- end
41
-
42
8
  class Scope
43
9
  attr_accessor :env
44
10
  def initialize(env)
@@ -47,11 +13,16 @@ module Wunderbar
47
13
  end
48
14
 
49
15
  @@templates = {}
16
+ @@files = {}
50
17
 
51
18
  def self.templates
52
19
  @@templates
53
20
  end
54
21
 
22
+ def self.files
23
+ @@files
24
+ end
25
+
55
26
  module API
56
27
  def _html(*args, &block)
57
28
  Wunderbar.html(*args, &block)
@@ -77,6 +48,11 @@ module Wunderbar
77
48
  def _template(name, &block)
78
49
  Wunderbar.templates[name.to_s.gsub('_','-')] = block
79
50
  end
51
+
52
+ def _file(name, options={}, &block)
53
+ options[:source] = block if block
54
+ Wunderbar.files[name] = options
55
+ end
80
56
  end
81
57
 
82
58
  #
@@ -133,7 +133,7 @@ module Wunderbar
133
133
  # * Proxied Rack server. Document base may be relate to the
134
134
  # HTTP_X_WUNDERBAR_BASE
135
135
  #
136
- cwd = File.realpath(Dir.pwd.untaint)
136
+ cwd = File.realpath(Dir.pwd)
137
137
  base = @_scope.env['DOCUMENT_ROOT'] if @_scope.env.respond_to? :[]
138
138
  base ||= cwd
139
139
  href = (head.children[1].attrs[:href] || '')
@@ -189,8 +189,8 @@ module Wunderbar
189
189
  name = name.to_s.gsub('_', '-')
190
190
 
191
191
  if flag != '!'
192
- if String === args.first and args.first.respond_to? :html_safe?
193
- if args.first.html_safe? and not block and args.first =~ /[>&]/
192
+ if String === args.first
193
+ if not block and args.first =~ /[>&]/
194
194
  markup = args.shift
195
195
  block = Proc.new {_ {markup}}
196
196
  end
@@ -362,11 +362,7 @@ module Wunderbar
362
362
  def _(text=nil, &block)
363
363
  unless block
364
364
  if text
365
- if text.respond_to? :html_safe? and text.html_safe?
366
- _ {text}
367
- else
368
- @_x.indented_text! text.to_s
369
- end
365
+ _ {text}
370
366
  end
371
367
  return @_x
372
368
  end
@@ -374,20 +370,13 @@ module Wunderbar
374
370
  children = instance_eval(&block)
375
371
 
376
372
  if String === children
377
- safe = !children.tainted?
378
- safe ||= children.html_safe? if children.respond_to? :html_safe?
379
- safe &&= defined? Nokogiri
380
- ok = safe || defined? Sanitize
381
- safe = true
382
-
383
- if ok and (children.include? '<' or children.include? '&')
373
+ if children.include? '<' or children.include? '&'
384
374
  if defined? Nokogiri::HTML5.fragment
385
375
  doc = Nokogiri::HTML5.fragment(children.to_s)
386
376
  else
387
377
  doc = Nokogiri::HTML.fragment(children.to_s)
388
378
  end
389
379
 
390
- Sanitize.new.clean_node! doc.dup.untaint if not safe
391
380
  children = doc.children.to_a
392
381
 
393
382
  # ignore leading whitespace
@@ -25,7 +25,7 @@ module Wunderbar
25
25
  # clear environment of cgi cruft
26
26
  require 'cgi'
27
27
  ENV.keys.select {|key| key =~ /^HTTP_/}.each do |key|
28
- ENV.delete key.dup.untaint
28
+ ENV.delete key
29
29
  end
30
30
  ::CGI::QueryExtension.public_instance_methods.each do |method|
31
31
  ENV.delete method.to_s.upcase
@@ -1,5 +1,6 @@
1
1
  require 'wunderbar'
2
2
  require 'rack'
3
+ require 'rack/media_type'
3
4
 
4
5
  module Wunderbar
5
6
  class RackApp
@@ -9,8 +10,13 @@ module Wunderbar
9
10
  @_request = Rack::Request.new(env)
10
11
  @_response = Rack::Response.new
11
12
  Wunderbar.logger = @_request.logger
12
- if Wunderbar.safe? and $SAFE==0
13
- Proc.new { $SAFE=1; Wunderbar::CGI.call(self) }.call
13
+ file = Wunderbar.files[env['PATH_INFO']]
14
+
15
+ if file
16
+ mime = file[:mime] ||
17
+ Rack::Mime::MIME_TYPES[File.extname(env['PATH_INFO'])]
18
+ @_response.set_header('Content-Type', mime) if mime
19
+ @_response.write(file[:content] || file[:source].call)
14
20
  else
15
21
  Wunderbar::CGI.call(self)
16
22
  end
@@ -43,6 +49,12 @@ module Wunderbar
43
49
  def response
44
50
  @_response
45
51
  end
52
+
53
+ %w(delete get head options post put trace).each do |http_method|
54
+ define_method "#{http_method}?" do
55
+ @_env['REQUEST_METHOD'].to_s.downcase == http_method
56
+ end
57
+ end
46
58
  end
47
59
  end
48
60
 
@@ -7,7 +7,7 @@ module Wunderbar
7
7
  cattr_accessor :default_format
8
8
  self.default_format = Mime[:html]
9
9
 
10
- def self.call(template)
10
+ def self.call(template, source=nil)
11
11
  %{
12
12
  compiled = Proc.new {#{template.source}}
13
13
  x = Wunderbar::HtmlMarkup.new(self);
@@ -24,7 +24,7 @@ module Wunderbar
24
24
  cattr_accessor :default_format
25
25
  self.default_format = Mime[:json]
26
26
 
27
- def self.call(template)
27
+ def self.call(template, source=nil)
28
28
  %{
29
29
  compiled = Proc.new {#{template.source}}
30
30
  x = Wunderbar::JsonBuilder.new(self);
@@ -16,6 +16,12 @@ class Wunderbar::Render
16
16
  "ReactDOMServer.renderToString(#{common})"
17
17
  end
18
18
 
19
+ # return all nodes on server rendering, as there is no wrapper element
20
+ # like there is for vue
21
+ def self.extract(nodes)
22
+ nodes
23
+ end
24
+
19
25
  def self.client(common, element, target)
20
26
  "ReactDOM.render(#{common}, #{element})"
21
27
  end
@@ -29,17 +35,3 @@ class Wunderbar::Render
29
35
  "</pre>"
30
36
  end
31
37
  end
32
-
33
- # Monkeypatch to address https://github.com/sstephenson/execjs/pull/180
34
- require 'execjs'
35
- class ExecJS::ExternalRuntime::Context
36
- alias_method :w_write_to_tempfile, :write_to_tempfile
37
- def write_to_tempfile(*args)
38
- tmpfile = w_write_to_tempfile(*args).path.untaint
39
- tmpfile = Struct.new(:path, :to_str).new(tmpfile, tmpfile)
40
- def tmpfile.unlink
41
- File.unlink path
42
- end
43
- tmpfile
44
- end
45
- end
@@ -82,14 +82,12 @@ class Wunderbar::XmlMarkup
82
82
 
83
83
  src = File.join(base, src) if not base.empty?
84
84
  src = src.sub(/\?.*$/, '') # strip queries (typically mtimes)
85
- src.untaint
86
85
 
87
- name = File.expand_path(src, @_scope.settings.public_folder.untaint)
88
- name.untaint unless src.tainted?
86
+ name = File.expand_path(src, @_scope.settings.public_folder)
89
87
  if File.exist? name
90
88
  result = File.read(name)
91
89
  else
92
- file = File.expand_path(src+'.rb', @_scope.settings.views.untaint)
90
+ file = File.expand_path(src+'.rb', @_scope.settings.views)
93
91
  result = Wunderbar::Asset.convert(file)
94
92
  end
95
93
  else
@@ -113,11 +111,11 @@ class Wunderbar::XmlMarkup
113
111
  scripts.unshift script.contents
114
112
  elsif script.path
115
113
  if script.path.start_with? '/'
116
- path = (ENV['DOCUMENT_ROOT'] + script.path).untaint
114
+ path = ENV['DOCUMENT_ROOT'] + script.path
117
115
  else
118
- path = File.expand_path(script.path, Wunderbar::Asset.root).untaint
116
+ path = File.expand_path(script.path, Wunderbar::Asset.root)
119
117
  end
120
- setup << File.read(script.options[:server].untaint || path)
118
+ setup << File.read(script.options[:server] || path)
121
119
  end
122
120
  end
123
121
 
@@ -131,7 +129,7 @@ class Wunderbar::XmlMarkup
131
129
  html = Wunderbar::Render.eval(scripts, server)
132
130
 
133
131
  # insert results into target
134
- nodes = builder._ { html }
132
+ nodes = Wunderbar::Render.extract(builder._ { html })
135
133
 
136
134
  begin
137
135
  if nodes.length == 1
@@ -82,22 +82,14 @@ module Wunderbar
82
82
  builder.set_variables_from_params(locals)
83
83
 
84
84
  if not block
85
- builder.instance_eval(data.untaint, eval_file)
85
+ builder.instance_eval(data, eval_file)
86
86
  elsif not data
87
87
  builder.instance_eval(&block)
88
88
  else
89
89
  context = builder.get_binding do
90
90
  builder.instance_eval {_(&block)}
91
91
  end
92
- context.eval(data.untaint, eval_file)
93
- end
94
- end
95
-
96
- def _evaluate_safely(*args, &block)
97
- if Wunderbar.safe? and $SAFE==0
98
- Proc.new { $SAFE=1; _evaluate(*args, &block) }.call
99
- else
100
- _evaluate(*args, &block)
92
+ context.eval(data, eval_file)
101
93
  end
102
94
  end
103
95
  end
@@ -108,7 +100,7 @@ module Wunderbar
108
100
  def evaluate(scope, locals, &block)
109
101
  builder = HtmlMarkup.new(scope)
110
102
  begin
111
- _evaluate_safely(builder, scope, locals, &block)
103
+ _evaluate(builder, scope, locals, &block)
112
104
  rescue Exception => exception
113
105
  scope.response.status = Wunderbar::ServerError.status
114
106
  builder.clear!
@@ -132,7 +124,7 @@ module Wunderbar
132
124
  def evaluate(scope, locals, &block)
133
125
  builder = JsonBuilder.new(scope)
134
126
  begin
135
- result = _evaluate_safely(builder, scope, locals, &block)
127
+ result = _evaluate(builder, scope, locals, &block)
136
128
 
137
129
  # if no output was produced, use the result
138
130
  builder._! result if builder.target? == {} and result
@@ -154,7 +146,7 @@ module Wunderbar
154
146
  def evaluate(scope, locals, &block)
155
147
  builder = TextBuilder.new(scope)
156
148
  begin
157
- result = _evaluate_safely(builder, scope, locals, &block)
149
+ result = _evaluate(builder, scope, locals, &block)
158
150
 
159
151
  # if no output was produced, use the result
160
152
  builder._ result.to_s if builder.target!.empty? and result
@@ -240,13 +232,12 @@ Tilt.register 'xhtml.rb', Wunderbar::Template::Xhtml
240
232
  helpers Wunderbar::SinatraHelpers
241
233
 
242
234
  if Dir.exist? settings.public_folder
243
- Wunderbar::Asset.root = File.join(settings.public_folder, 'assets').untaint
235
+ Wunderbar::Asset.root = File.join(settings.public_folder, 'assets')
244
236
  end
245
237
 
246
238
  Wunderbar::Asset.virtual = true
247
239
 
248
240
  get "/#{Wunderbar::Asset.path}/:name" do |name|
249
- name.untaint if name =~ /^([-\w]\.?)+$/
250
241
  file = "#{Wunderbar::Asset.root}/#{name}"
251
242
  _text do
252
243
  if File.exist? file
@@ -1,7 +1,7 @@
1
1
  module Wunderbar
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
- MINOR = 3
4
+ MINOR = 4
5
5
  TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
@@ -14,17 +14,30 @@ class Wunderbar::Render
14
14
  path = `which nodejs`.chomp
15
15
  path = `which node`.chomp if path.empty?
16
16
  raise RuntimeError.new('Unable to locate nodejs') if path.empty?
17
- @nodejs = path.untaint
17
+ @nodejs = path
18
18
  end
19
19
 
20
20
  def self.server(common)
21
- "VueServer.renderToString(new Vue({render: function($h) {return #{common}}}))"
21
+ "VueServer.renderToString(new Vue({render: function($h) {
22
+ return $h('div', #{common})}}))"
23
+ end
24
+
25
+ # unwrap children from div wrapper inserted by self.server
26
+ def self.extract(nodes)
27
+ if
28
+ nodes.length == 1 and nodes.first.name == 'div' and
29
+ nodes.first.attrs['data-server-rendered'].to_s == 'true'
30
+ then
31
+ nodes.first.children
32
+ else
33
+ nodes
34
+ end
22
35
  end
23
36
 
24
37
  def self.client(common, element, target)
25
38
  wrap = "$h(#{target.name.inspect}, " +
26
39
  "{attrs: {#{target.attrs.map {|name, value|
27
- "#{name}: #{value.inspect}"}.join(', ')}}}, [#{common}])"
40
+ "#{name}: #{value.inspect}"}.join(', ')}}}, #{common})"
28
41
  "new Vue({el: #{element}, render: function($h) {return #{wrap}}})"
29
42
  end
30
43
 
@@ -37,7 +50,7 @@ class Wunderbar::Render
37
50
  stdout += "\n<pre>#{CGI.escapeHTML(stderr)}</pre>"
38
51
  end
39
52
 
40
- stdout.untaint
53
+ stdout
41
54
  rescue => e
42
55
  Wunderbar.error e
43
56
  "<pre>#{CGI.escapeHTML(e.message)}</pre>"
@@ -1,21 +1,23 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: wunderbar 1.3.0 ruby lib
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $:.unshift lib unless $:.include?(lib)
4
+ require 'wunderbar/version'
3
5
 
4
6
  Gem::Specification.new do |s|
5
7
  s.name = "wunderbar".freeze
6
- s.version = "1.3.0"
8
+ s.version = Wunderbar::VERSION::STRING
7
9
 
8
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
11
  s.require_paths = ["lib".freeze]
10
12
  s.authors = ["Sam Ruby".freeze]
11
- s.date = "2019-03-06"
13
+ s.date = "2019-06-07"
12
14
  s.description = " Wunderbar makes it easy to produce valid HTML5, wellformed XHTML, Unicode\n (utf-8), consistently indented, readable applications.'\n".freeze
13
15
  s.email = "rubys@intertwingly.net".freeze
14
16
  s.files = ["COPYING".freeze, "README.md".freeze, "lib/wunderbar".freeze, "lib/wunderbar.rb".freeze, "lib/wunderbar/asset.rb".freeze, "lib/wunderbar/backtick.rb".freeze, "lib/wunderbar/bootstrap".freeze, "lib/wunderbar/bootstrap.rb".freeze, "lib/wunderbar/bootstrap/theme.rb".freeze, "lib/wunderbar/builder.rb".freeze, "lib/wunderbar/cgi-methods.rb".freeze, "lib/wunderbar/coderay.rb".freeze, "lib/wunderbar/coffeescript.rb".freeze, "lib/wunderbar/cssproxy.rb".freeze, "lib/wunderbar/environment.rb".freeze, "lib/wunderbar/eventsource.rb".freeze, "lib/wunderbar/html-methods.rb".freeze, "lib/wunderbar/installation.rb".freeze, "lib/wunderbar/job-control.rb".freeze, "lib/wunderbar/jquery".freeze, "lib/wunderbar/jquery.rb".freeze, "lib/wunderbar/jquery/filter.rb".freeze, "lib/wunderbar/jquery/stupidtable.rb".freeze, "lib/wunderbar/listen.rb".freeze, "lib/wunderbar/logger.rb".freeze, "lib/wunderbar/markdown.rb".freeze, "lib/wunderbar/marked.rb".freeze, "lib/wunderbar/node.rb".freeze, "lib/wunderbar/pagedown.rb".freeze, "lib/wunderbar/polymer.rb".freeze, "lib/wunderbar/rack.rb".freeze, "lib/wunderbar/rails.rb".freeze, "lib/wunderbar/react.rb".freeze, "lib/wunderbar/render.rb".freeze, "lib/wunderbar/script.rb".freeze, "lib/wunderbar/server.rb".freeze, "lib/wunderbar/sinatra.rb".freeze, "lib/wunderbar/underscore.rb".freeze, "lib/wunderbar/vendor".freeze, "lib/wunderbar/vendor/Markdown.Converter.js".freeze, "lib/wunderbar/vendor/bootstrap-theme.min.css".freeze, "lib/wunderbar/vendor/bootstrap.min.css".freeze, "lib/wunderbar/vendor/bootstrap.min.js".freeze, "lib/wunderbar/vendor/eventsource.min.js".freeze, "lib/wunderbar/vendor/jquery-3.2.1.min.js".freeze, "lib/wunderbar/vendor/marked.min.js".freeze, "lib/wunderbar/vendor/polymer-v0.0.20131003.min.js".freeze, "lib/wunderbar/vendor/react-dom-server.min.js".freeze, "lib/wunderbar/vendor/react-dom.min.js".freeze, "lib/wunderbar/vendor/react-with-addons.min.js".freeze, "lib/wunderbar/vendor/stupidtable.min.js".freeze, "lib/wunderbar/vendor/underscore-min.js".freeze, "lib/wunderbar/vendor/vue-server.min.js".freeze, "lib/wunderbar/vendor/vue.min.js".freeze, "lib/wunderbar/version.rb".freeze, "lib/wunderbar/vue.rb".freeze, "lib/wunderbar/websocket.rb".freeze, "wunderbar.gemspec".freeze]
15
17
  s.homepage = "http://github.com/rubys/wunderbar".freeze
16
18
  s.licenses = ["MIT".freeze]
17
19
  s.required_ruby_version = Gem::Requirement.new(">= 1.9.3".freeze)
18
- s.rubygems_version = "2.7.6".freeze
20
+ s.rubygems_version = "3.0.6".freeze
19
21
  s.summary = "HTML Generator and CGI application support".freeze
20
22
 
21
23
  if s.respond_to? :specification_version then
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wunderbar
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Ruby
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-06 00:00:00.000000000 Z
11
+ date: 2019-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -105,8 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  - !ruby/object:Gem::Version
106
106
  version: '0'
107
107
  requirements: []
108
- rubyforge_project:
109
- rubygems_version: 2.7.6
108
+ rubygems_version: 3.1.2
110
109
  signing_key:
111
110
  specification_version: 4
112
111
  summary: HTML Generator and CGI application support