jscall 1.0.1 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97c7ab8cd5d710cfca8c77f6e906643252b9c54cc5973709763b89aef3830dee
4
- data.tar.gz: e205fad16cc87df640b186ac99190186374f2db821a7e3d499563add9016b097
3
+ metadata.gz: dad6ca4017b93ba7f1675b3d1e3727a143d5e413f86d9f000966f7eae9306d06
4
+ data.tar.gz: e50ef13d47441f195194e4a36886b506266f87339f9d7bbf7f5b9d79dc500814
5
5
  SHA512:
6
- metadata.gz: f25ebf232e77432bb5c79f511c4fc99de78e2d7861e4d3831edcf3662e747021d5d4a207036c8a7add2fe1822c9fb8fdb7439b1e17e67627abea090c1285662c
7
- data.tar.gz: 8e02fe7a9f3d7f0d82ac70f24d33335c2dffe1261133e2dec4a1c4ff65ec9b87bb9fad8f0049dee3fb681c20e7b3f47d9a97890b45958199f1e78c0b76fd69b5
6
+ metadata.gz: 16a7885d6e0e5ef993a9f8ea43a6dc2bcfe78624f20cd10517642c00f59525b1edab1a91ab99367f962d3f63ba5a5c6705bf7cad915673613fb9ee805358baeb
7
+ data.tar.gz: 1f7d95224652882839fd9bce1d4fd539021980018ecc1cca73aed56e598a2c034b8800cdfb88cc6ffd4b09f6488867e33335e8180f7e5e81aa29663ebdc6a5d4
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Jscall
2
2
 
3
+ [![Ruby](https://github.com/csg-tokyo/jscall/actions/workflows/ruby.yml/badge.svg)](https://github.com/csg-tokyo/jscall/actions/workflows/ruby.yml)
4
+
3
5
  Jscall allows executing a program in JavaScript on node.js or a web browser.
4
6
  By default, node.js is used for the execution.
5
7
  To choose a web browser, call `Jscall.config`.
@@ -16,13 +18,17 @@ Jscall.exec '1 + 1'
16
18
  ```
17
19
 
18
20
  This returns `2`. The argument passed to `Jscall.exec` can be
19
- multipe lines. It is executed as source code written in JavaScript.
21
+ multiple lines. It is executed as source code written in JavaScript.
20
22
 
21
23
  `Jscall.exec` returns a resulting value. Numbers, character strings (and symbols), boolean values, and `nil` (and `null`)
22
- are copied when passing between Ruby and JavaScript. An array is also shallow-copied.
24
+ are copied when passing between Ruby and JavaScript. An array is shallow-copied.
23
25
  Other objects are not copied. When they are passed, a remote reference is created at the destination.
26
+ When a `Map` object is returned from JavaScript to Ruby, it is also
27
+ shallow-copied but into a `Hash` object in Ruby.
24
28
 
25
- A remote reference is a proxy object. A method call on a remote reference invokes a method on the corresponding object on the remote site. For example,
29
+ A remote reference is a local reference to a proxy object.
30
+ A method call on a remote reference invokes a method on the corresponding
31
+ object on the remote site. For example,
26
32
 
27
33
  ```
28
34
  js_obj = Jscall.exec '({ foo: (x) => x + 1, bar: 7 })'
@@ -35,11 +41,30 @@ js_obj.baz # 9
35
41
  The `foo` method is executed in JavaScript.
36
42
  Since `bar` is not a function, its value is returned to Ruby as it is.
37
43
 
38
- Setting a object property to a given value is also
44
+ Setting an object property to a given value is also
39
45
  allowed. The expression `js_obj.baz = 9` above sets
40
46
  the object property `baz` to 9.
41
47
 
42
- To call a JavaScript function from Ruby, call a mehtod on `Jscall`.
48
+ An argument to a JavaScript method is copied from Ruby to
49
+ JavaScript unless it is an object. When an argument is a Ruby object,
50
+ a proxy object is created in JavaScript. The rule is the same as the
51
+ rule for returning a value from JavaScript to Ruby. A primitive
52
+ value is copied but an object is not. An array is shallow-copied.
53
+
54
+ A `Hash` object in Ruby is also shallow-copied into JavaScript but a normal
55
+ object is created in JavaScript. Recall that a JavaScript object is
56
+ regarded as an associative array, or a hash table as in Ruby.
57
+ For example, in Ruby,
58
+
59
+ ```
60
+ obj = { a: 2, b: 3 }
61
+ ```
62
+
63
+ when this ruby object is passed to JavaScript as an argument,
64
+ a normal object `{ a: 2, b: 3 }` is created as its copy in JavaScript
65
+ and passed to a JavaScript method.
66
+
67
+ To call a JavaScript function from Ruby, call a method on `Jscall`.
43
68
  For example,
44
69
 
45
70
  ```
@@ -54,9 +79,22 @@ Jscall.foo(7) # 8
54
79
  `Jscall.foo(7)` invokes the JavaScript function with the name following `Jscall.`
55
80
  with the given argument. In this case,
56
81
  the `foo` function is executed with the argument `7`.
82
+ Arguments and a return value are passed to/from a function
83
+ as they are passed to/from a method.
84
+
85
+ `Jscall` can be used for obtaining a remote reference to access a global variable
86
+ in JavaScript. For example,
87
+
88
+ ```
89
+ Jscall.console.log('Hello')
90
+ ```
91
+
92
+ This prints `Hello` on a JavaScript console. `Jscall.console` returns a remote
93
+ reference to the value of `console` in JavaScript. Then, `.log('Hello')`
94
+ calls the `log` method on `console` in JavaScript.
57
95
 
58
96
  When a Ruby object is passed to a JavaScript function/method,
59
- it can call a method on the passed Ruby object.
97
+ you can call a method on the passed Ruby object.
60
98
 
61
99
  ```
62
100
  Jscall.exec <<CODE
@@ -72,7 +110,7 @@ created in Ruby.
72
110
  Note that you must `await` every call to Ruby object since it is
73
111
  asynchronous call.
74
112
 
75
- In JavaScript, `Ruby.exec` is availale to run a program in Ruby.
113
+ In JavaScript, `Ruby.exec` is available to run a program in Ruby.
76
114
  For example,
77
115
 
78
116
  ```
@@ -84,10 +122,19 @@ CODE
84
122
  Jscall.foo()
85
123
  ```
86
124
 
87
- `Jscall.foo()` returns the result of evaluating `RUBY_VERSION`
88
- in Ruby.
125
+ `Jscall.foo()` returns the result of evaluating given Ruby code
126
+ `RUBY_VERSION` in Ruby.
89
127
  Don't forget to `await` a call to `Ruby.exec`.
90
128
 
129
+ ### Remote references
130
+
131
+ A remote reference is implemented by a local reference to a proxy
132
+ object representing the remote object that the remote reference refers to.
133
+ When a proxy object is passed as an argument or a return value
134
+ from Ruby to JavaScript (or vice versa), the corresponding JavaScript
135
+ (or Ruby) object is passed to the destination. In other words,
136
+ a remote reference passed is converted back to a local reference.
137
+
91
138
  Remote references will be automatically reclaimed when they are no
92
139
  longer used. To reclaim them immediately, call:
93
140
 
@@ -95,6 +142,25 @@ longer used. To reclaim them immediately, call:
95
142
  Jscall.scavenge_references
96
143
  ```
97
144
 
145
+ As mentioned above, a remote reference is a local reference
146
+ to a proxy object. In Ruby,
147
+ even a proxy object provides a number of methods inherited from `Object` class,
148
+ such as `clone`, `to_s`, and `inspect`. A call to such a method is not
149
+ delegated to the corresponding JavaScript object. To invoke such a method
150
+ on a JavaScript object, call `send` on its proxy object.
151
+ For example,
152
+
153
+ ```
154
+ js_obj = Jscall.exec '({ to_s: (x, y) => x + y })'
155
+ puts js_obj.to_s(3, 4) # error
156
+ puts js_obj.send('to_s', 3, 4) # 7
157
+ ```
158
+
159
+ The `send` method invokes the JavaScript method with the name specified
160
+ by the first argument. The remaining arguments passed to `send` are passed
161
+ to that JavaScript method.
162
+
163
+
98
164
  ## DOM manipulation
99
165
 
100
166
  When JavaScript code is run on a browser, some utility methods
@@ -109,7 +175,16 @@ links `mystyle.css` in the current directory.
109
175
  - `Jscall.dom.print(msg)`
110
176
 
111
177
  This adds a `p` element to the DOM tree.
178
+ Its inner text is the character string passed as `msg`.
112
179
 
180
+ - `Jscall.dom.append_to_body(html_source)`
181
+
182
+ This inserts the given `html_source` at the end of the `body` element.
183
+ It is a shorthand for
184
+
185
+ ```
186
+ Jscall.document.body.insertAdjacentHTML('beforeend', html_source)
187
+ ```
113
188
 
114
189
  ## Variable scope
115
190
 
@@ -142,16 +217,33 @@ for loading a CommonJS module. For example,
142
217
  Jscall.exec "mime = require('./mime.js')"
143
218
  ```
144
219
 
145
- The file `./mime.js` is loaded and the module is bound to a global variable `mime`.
220
+ The file `./mime.js` is loaded and the module is bound to a global variable `mime` in JavaScript.
146
221
 
147
- You may want to call `Jscall.dyn_import` in Ruby.
222
+ You can directly call `require` on `Jscall` in Ruby.
223
+
224
+ ```
225
+ parser = Jscall.require("@babel/parser")
226
+ ast = parser.parse('const i = 3')
227
+ Jscall.console.log(ast)
228
+ ```
229
+
230
+ `require` will search `./node_modules/` for `@babel/parser`.
231
+ This is equivalent to the following JavaScript code.
232
+
233
+ ```
234
+ parser = require("@babel/parser")
235
+ ast = parser.parse('const i = 3')
236
+ console.log(ast)
237
+ ```
238
+
239
+ Dynamic importing is also available. Call `Jscall.dyn_import` in Ruby.
148
240
 
149
241
  ```
150
242
  fs = Jscall.dyn_import('fs')
151
243
  ```
152
244
 
153
245
  This executes dynamic importing in JavaScript.
154
- For node.js, the file name of the imported module should be a full path name. For a web browser, the root directory is a current working directory. So `Jscall.dyn_import('/mine.mjs')` loads the file `./mine.mjs`.
246
+ For node.js, the file name of the imported module should be a full path name. For a web browser, the root directory is the current working directory. So `Jscall.dyn_import('/mine.mjs')` loads the file `./mine.mjs`.
155
247
 
156
248
  `Jscall.dyn_import` takes the second argument. If it is given,
157
249
  a global variable in JavaScript is bound to the loaded module.
@@ -166,49 +258,147 @@ This is quite equivalent to the following JavaScript code:
166
258
  fs_module = await load('fs')
167
259
  ```
168
260
 
261
+ ## Promise
262
+
263
+ If a program attempts to pass a `Promise` object from JavaScript to Ruby,
264
+ it waits until the promise is fulfilled. Then Jscall passes
265
+ the value of that promise from JavaScript to Ruby instead of that
266
+ promise itself (or a remote reference to that promise). When that promise
267
+ is rejected, an error object is passed to Ruby
268
+ so that the error will be raised in Ruby.
269
+ This design reflects the fact that an `async` function in JavaScript
270
+ also returns a `Promise` object but this object must not be returned
271
+ to Ruby as is when that `async` function is called from Ruby.
272
+ Jscall cannot determine whether a promise should be passed as is to Ruby
273
+ or its value must be passed to Ruby after the promise is fulfilled.
274
+
275
+ When enforcing Jscall to pass a `Promise` object from JavaScript to Ruby,
276
+ `.async` must be inserted between a receiver and a method name.
277
+
278
+ ```
279
+ Jscall.exec(<<CODE)
280
+ function make_promise() {
281
+ return { a: Promise.resolve(7) }
282
+ }
283
+ CODE
284
+
285
+ obj = Jscall.make_promise
286
+ result = obj.a # 7
287
+ prom = obj.async.a # promise
288
+ prom.then(->(r) { puts r }) # 7
289
+ ```
290
+
291
+ ## Synchronous calls
292
+
293
+ You might want to avoid writing `await` when you call a method on a Ruby
294
+ object or you execute Ruby code by `Ruby.exec` from JavaScript.
295
+ For example, that call is included in library code and you might not
296
+ be able to modify the library code so that `await` will be inserted.
297
+
298
+ Jscall supports synchronous calls from JavaScript to Ruby only when
299
+ the underlying JavaScript engine is node.js on Linux.
300
+ In the mode of synchronous calls, you do not have to `await` a method call
301
+ on a Ruby object or a call to `Ruby.exec`.
302
+ It blocks until the return value comes back from Ruby.
303
+ While it blocks, all calls from Ruby to JavaScript are
304
+ synchronously processed.
305
+
306
+ To change to the mode of synchronous calls,
307
+ call `Jscall.config`:
308
+
309
+ ```
310
+ Jscall.config(sync: true)
311
+ ```
169
312
 
170
313
  ## Configuration
171
314
 
172
- To import JavaScript modules when node.js starts,
315
+ Jscall supports several configuration options.
316
+ Call `Jscall.config` with necessary options.
317
+
318
+ ### module_names:
319
+
320
+ To import JavaScript modules when node.js or a web browser starts,
173
321
 
174
322
  ```
175
- Jscall.config(module_names: [["Foo", "./foo.mjs"], ["Bar", "./bar.mjs"]], options: "--use-strict")
323
+ Jscall.config(module_names: [["Foo", "./js", "/lib/foo.mjs"], ["Bar", "./js", "/lib/bar.mjs"]])
176
324
  ```
177
325
 
178
- This specifies that `./foo.mjs` and `./bar.mjs` are impoted when node.js starts.
326
+ This specifies that `./js/lib/foo.mjs` and `./js/lib/bar.mjs` are imported
327
+ at the beginning.
179
328
  This is equivalent to the following import declarations:
180
329
 
181
330
  ```
182
- import * as "Foo" from "./foo.mjs"
183
- import * as "Bar" from "./bar.mjs"
331
+ import * as "Foo" from "./js/lib/foo.mjs"
332
+ import * as "Bar" from "./js/lib/bar.mjs"
184
333
  ```
185
334
 
186
- `'--use-strict'` is passed to node.js as a command line argument.
335
+ Note that each array element given to `module_names:` is
187
336
 
188
- `module_names:` and `options:` are optional arguments to `Jscall.config`.
337
+ ```
338
+ [<module_name> <root> <path>]
339
+ ```
189
340
 
190
- To change the name of the node command,
341
+ `<path>` must start with `/`. It is used as a part of the URL when a browser
342
+ accesses a module.
343
+ When importing a module for node.js, `<root>` and `<path>` are concatenated
344
+ to form a full path name.
345
+
346
+ `<path>` must not start with `/jscall` or `/cmd`. They are reserved for
347
+ internal use.
348
+
349
+ ### options:
350
+
351
+ To specify a command line argument passed to node.js,
191
352
 
192
353
  ```
193
- Jscall::PipeToJs.node_command = "node.exe"
354
+ Jscall.config(options: '--use-strict')
194
355
  ```
195
356
 
196
- The default command name is `"node"`.
357
+ This call specifies that
358
+ `--use-strict` is passed as a command line argument.
359
+
360
+ ### browser: and port:
197
361
 
198
362
  When running JavaScript code on a web browser,
199
363
 
200
364
  ```
201
- Jscall.config(browser: true, options: {port: 10082})
365
+ Jscall.config(browser: true, port: 10082)
202
366
  ```
203
367
 
204
- `options:` is an optional argument.
368
+ Passing `true` for `browser:` switches the execution engine to a web browser.
369
+ The default engine is node.js.
370
+ To switch the engine back to node.js, pass `false` for `browser:`.
371
+ Call `Jscall.close` to detach the current execution engine.
372
+ A new engine with a new configuration will be created.
373
+
374
+ `port:` specifies the port number of an http server. It is optional.
205
375
  The example above specifies that Ruby receives http requests
206
376
  sent to http://localhost:10082 from JavaScript on a web browser.
207
377
 
208
- Passing `false` for `browser:` to `Jscall.config` switches
209
- the execution engine to node.js.
210
- Call `Jscall.close` to detach the current execution engine.
211
- A new enigine with a new configuration will be created.
378
+
379
+ ### Misc.
380
+
381
+ To change to the mode of synchronous calls,
382
+
383
+ ```
384
+ Jscall.config(sync: true)
385
+ ```
386
+
387
+ To set all the configurations to the default ones,
388
+
389
+ ```
390
+ Jscall.config()
391
+ ```
392
+
393
+ ### Other configurations
394
+
395
+ To change the name of the node command,
396
+
397
+ ```
398
+ Jscall::PipeToJs.node_command = "node.exe"
399
+ ```
400
+
401
+ The default command name is `"node"`.
212
402
 
213
403
  To change the command for launching a web browser,
214
404
 
@@ -224,6 +414,12 @@ Jscall launches a web browser by the command like the following:
224
414
  open http://localhost:10082/jscall/jscall.html
225
415
  ```
226
416
 
417
+ Jscall generates a verbose error message if its debug level is more than 0.
418
+
419
+ ```
420
+ Jscall.debug = 1
421
+ ```
422
+
227
423
  ## Installation
228
424
 
229
425
  Add this line to your application's Gemfile:
@@ -254,7 +450,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/csg-to
254
450
 
255
451
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
256
452
 
257
- ## Acknowledgement
453
+ ## Acknowledgment
258
454
 
259
455
  The icon image for jscall was created by partly using the Ruby logo, which was obtained
260
456
  from https://www.ruby-lang.org/en/about/logo/ under CC BY-SA 2.5.
@@ -0,0 +1,56 @@
1
+ # Display a pdf file by using pdf.js
2
+
3
+ require 'jscall'
4
+
5
+ # Run a JavaScript program on a browser
6
+ Jscall.config browser: true
7
+
8
+ # Write HTML code on a blank web page.
9
+ Jscall.dom.append_to_body(<<CODE)
10
+ <h1>PDF.js 'Hello, world!' example</h1>
11
+ <canvas id="the-canvas"></canvas>
12
+ CODE
13
+
14
+ # import pdf.js
15
+ pdfjs = Jscall.dyn_import('https://mozilla.github.io/pdf.js/build/pdf.js')
16
+
17
+ # A pdf file
18
+ url = "https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf"
19
+
20
+ pdf = Jscall.exec 'window["pdfjs-dist/build/pdf"]'
21
+
22
+ pdf.GlobalWorkerOptions.workerSrc = "https://mozilla.github.io/pdf.js/build/pdf.worker.js"
23
+
24
+ loadingTask = pdf.getDocument(url)
25
+ loadingTask.async.promise.then(-> (pdf) {
26
+ puts "PDF loaded"
27
+
28
+ # Fetch the first page
29
+ pageNumber = 1;
30
+ pdf.async.getPage(pageNumber).then(-> (page) {
31
+ puts "Page loaded"
32
+
33
+ scale = 1.5;
34
+ viewport = page.getViewport({ scale: scale })
35
+
36
+ canvas = Jscall.document.getElementById("the-canvas")
37
+ context = canvas.getContext("2d")
38
+ canvas.height = viewport.height
39
+ canvas.width = viewport.width
40
+
41
+ # Render the pdf page
42
+ renderContext = {
43
+ canvasContext: context,
44
+ viewport: viewport,
45
+ }
46
+ renderTask = page.render(renderContext)
47
+ renderTask.async.promise.then(-> (r) {
48
+ # Print a message when the rendering succeeds.
49
+ puts "Page rendered #{r}"
50
+ })
51
+ })
52
+ },
53
+ -> (reason) {
54
+ # an error occurs.
55
+ puts reason
56
+ })
@@ -2,24 +2,27 @@
2
2
 
3
3
  export class HttpStream {
4
4
  constructor() {
5
- this.send_buffer = ['start']
5
+ this.recv_buffer = []
6
6
  this.send_callback = null
7
+ this.fetching = null
8
+ this.call_queue = []
9
+ this.puts('start')
7
10
  }
8
11
 
9
12
  [Symbol.asyncIterator]() {
10
13
  const http_stream = this
11
14
  return {
12
15
  next() {
13
- let msg = http_stream.send_buffer.shift()
14
- if (msg === undefined)
16
+ let next_data = http_stream.recv_buffer.shift()
17
+ if (next_data === undefined)
15
18
  return new Promise((resolve, reject) => {
16
19
  if (http_stream.send_callback === null)
17
20
  http_stream.send_callback = resolve
18
21
  else
19
22
  throw new Error('(fatal) send_callback is not null!')
20
- }).then(() => this.next())
23
+ })
21
24
  else
22
- return http_stream.do_fetch(msg)
25
+ return next_data
23
26
  }
24
27
  }
25
28
  }
@@ -40,12 +43,30 @@ export class HttpStream {
40
43
  }
41
44
 
42
45
  puts(msg) {
43
- this.send_buffer.push(msg)
44
- if (this.send_callback !== null) {
45
- const callback = this.send_callback
46
- this.send_callback = null
47
- callback()
48
- }
46
+ if (this.fetching === null)
47
+ this.fetching = this.puts0(msg)
48
+ else
49
+ this.call_queue.push(msg)
50
+ }
51
+
52
+ puts0(msg) {
53
+ return this.do_fetch(msg)
54
+ .then((data) => {
55
+ if (this.send_callback === null)
56
+ this.recv_buffer.push(data)
57
+ else {
58
+ const callback = this.send_callback
59
+ this.send_callback = null
60
+ callback(data)
61
+ }
62
+
63
+ if (this.call_queue.length > 0) {
64
+ const msg2 = this.call_queue.shift()
65
+ this.fetching = this.puts0(msg2)
66
+ }
67
+ else
68
+ this.fetching = null
69
+ })
49
70
  }
50
71
 
51
72
  setEncoding(encoding) {}
@@ -64,4 +85,8 @@ export const Jscall = new class {
64
85
  link.href = file_name
65
86
  document.head.append(link)
66
87
  }
88
+
89
+ append_to_body(html_source) {
90
+ document.body.insertAdjacentHTML('beforeend', html_source)
91
+ }
67
92
  }
@@ -8,6 +8,7 @@ module Jscall
8
8
  WEBrick::HTTPUtils::DefaultMimeTypes['mjs'] ||= "application/javascript"
9
9
 
10
10
  class Dom
11
+ # see Jscall class in browser.mjs
11
12
  def method_missing(name, *args)
12
13
  Jscall.__getpipe__.funcall(nil, "Jscall.#{name}", args)
13
14
  end
@@ -23,13 +24,27 @@ module Jscall
23
24
  end
24
25
 
25
26
  class PipeToBrowser < PipeToJs
26
- def startJS(module_names, options)
27
- port = 10081
28
- port = options[:port] if options.is_a?(Hash) && options.has_key?(:port)
29
- @pipe = FetchServer.new(port)
27
+ def startJS(module_names, config)
28
+ urls = {}
29
+ module_names.each_index do |i|
30
+ mod = module_names[i]
31
+ urls[mod[2]] = mod
32
+ end
33
+ port = config[:port] || 10081
34
+ @pipe = FetchServer.new(port, urls)
30
35
  @pipe.open
31
36
  end
32
37
 
38
+ def setup(config)
39
+ if config[:browser]
40
+ module_names = config[:module_names] || []
41
+ module_names.each_index do |i|
42
+ mod = module_names[i]
43
+ Jscall.dyn_import(mod[2], mod[0])
44
+ end
45
+ end
46
+ end
47
+
33
48
  def close
34
49
  @pipe.shutdown
35
50
  sleep(0.5)
@@ -58,7 +73,8 @@ module Jscall
58
73
  @@run_cmd = name
59
74
  end
60
75
 
61
- def initialize(port)
76
+ def initialize(port, urls)
77
+ @url_map = urls
62
78
  @send_buffer = Thread::Queue.new
63
79
  @receive_buffer = Thread::Queue.new
64
80
  @server_running = false
@@ -96,10 +112,16 @@ module Jscall
96
112
  end
97
113
 
98
114
  def read_file(req, res)
99
- if req.path.start_with?('/jscall/')
115
+ path = req.path
116
+ if path.start_with?('/jscall/')
100
117
  root = "#{__dir__}/../"
101
118
  else
102
- root = @server.config[:DocumentRoot]
119
+ value = @url_map[path]
120
+ if value.nil?
121
+ root = @server.config[:DocumentRoot]
122
+ else
123
+ root = value[1]
124
+ end
103
125
  end
104
126
  WEBrick::HTTPServlet::FileHandler.new(@server, root).service(req, res)
105
127
  end