sproutit-narwhal 0.1.106

Sign up to get free protection for your applications and to get access to all the features.
Files changed (291) hide show
  1. data/DISTRIBUTION.yml +15 -0
  2. data/README.md +86 -0
  3. data/Rakefile +349 -0
  4. data/VERSION.yml +7 -0
  5. data/bin/activate +50 -0
  6. data/bin/activate.bash +50 -0
  7. data/bin/activate.cmd +3 -0
  8. data/bin/js +67 -0
  9. data/bin/json +2 -0
  10. data/bin/narwhal +67 -0
  11. data/bin/narwhal.cmd +29 -0
  12. data/bin/sea +45 -0
  13. data/bin/sea.cmd +25 -0
  14. data/bin/tusk +2 -0
  15. data/bin/tusk.cmd +5 -0
  16. data/catalog.json +902 -0
  17. data/docs/available-packages.md +32 -0
  18. data/docs/browser-api-plan.md +290 -0
  19. data/docs/browser-api.md +153 -0
  20. data/docs/download.md +25 -0
  21. data/docs/engines.md +32 -0
  22. data/docs/json-tool.md +121 -0
  23. data/docs/lib/binary.wiki +242 -0
  24. data/docs/lib/file.wiki +325 -0
  25. data/docs/lib/os/popen.md +70 -0
  26. data/docs/modules.md +38 -0
  27. data/docs/narwhal.md +487 -0
  28. data/docs/packages-howto.md +32 -0
  29. data/docs/packages.md +30 -0
  30. data/docs/posts/2009-07-29-hello-0.1.md +19 -0
  31. data/docs/quick-start.md +69 -0
  32. data/docs/sea.md +49 -0
  33. data/engines/browser/lib/binary.js +2 -0
  34. data/engines/browser/lib/reactor.js +21 -0
  35. data/engines/browser/lib/system.js +3 -0
  36. data/engines/default/lib/array.js +164 -0
  37. data/engines/default/lib/binary-engine.js +53 -0
  38. data/engines/default/lib/binary.js +755 -0
  39. data/engines/default/lib/date.js +8 -0
  40. data/engines/default/lib/file-engine.js +119 -0
  41. data/engines/default/lib/function.js +119 -0
  42. data/engines/default/lib/global.js +11 -0
  43. data/engines/default/lib/io-engine.js +26 -0
  44. data/engines/default/lib/json.js +488 -0
  45. data/engines/default/lib/object.js +69 -0
  46. data/engines/default/lib/os-engine.js +3 -0
  47. data/engines/default/lib/reactor.js +12 -0
  48. data/engines/default/lib/string.js +84 -0
  49. data/engines/default/lib/system.js +20 -0
  50. data/engines/default/lib/worker.js +133 -0
  51. data/engines/jsc/README.md +18 -0
  52. data/engines/jsc/bootstrap.js +53 -0
  53. data/engines/jsc/deps/http-parser/LICENSE +77 -0
  54. data/engines/jsc/deps/http-parser/README.md +145 -0
  55. data/engines/jsc/deps/http-parser/http_parser.c +6087 -0
  56. data/engines/jsc/deps/http-parser/http_parser.h +141 -0
  57. data/engines/jsc/deps/http-parser/http_parser.rl +500 -0
  58. data/engines/jsc/deps/http-parser/test.c +858 -0
  59. data/engines/jsc/include/binary-engine.h +11 -0
  60. data/engines/jsc/include/io-engine.h +23 -0
  61. data/engines/jsc/include/narwhal.h +427 -0
  62. data/engines/jsc/lib/file-engine.js +31 -0
  63. data/engines/jsc/lib/http.js +1 -0
  64. data/engines/jsc/lib/io-engine.js +202 -0
  65. data/engines/jsc/lib/os-engine.js +25 -0
  66. data/engines/jsc/lib/system.js +18 -0
  67. data/engines/jsc/lib/zip.js +1 -0
  68. data/engines/jsc/narwhal-jsc.c +273 -0
  69. data/engines/jsc/narwhal.c +29 -0
  70. data/engines/jsc/package.json +8 -0
  71. data/engines/jsc/src/binary-engine.cc +290 -0
  72. data/engines/jsc/src/file-engine.cc +405 -0
  73. data/engines/jsc/src/io-engine.cc +423 -0
  74. data/engines/jsc/src/jack/handler/jill.cc +710 -0
  75. data/engines/jsc/src/os-engine.cc +210 -0
  76. data/engines/rhino/bin/narwhal-rhino +68 -0
  77. data/engines/rhino/bin/narwhal-rhino.cmd +34 -0
  78. data/engines/rhino/bootstrap.js +119 -0
  79. data/engines/rhino/jars/jline.jar +0 -0
  80. data/engines/rhino/jars/jna.jar +0 -0
  81. data/engines/rhino/jars/js.jar +0 -0
  82. data/engines/rhino/lib/binary-engine.js +83 -0
  83. data/engines/rhino/lib/concurrency.js +6 -0
  84. data/engines/rhino/lib/event-queue.js +18 -0
  85. data/engines/rhino/lib/file-engine.js +216 -0
  86. data/engines/rhino/lib/http-client-engine.js +90 -0
  87. data/engines/rhino/lib/http-engine.js +10 -0
  88. data/engines/rhino/lib/io-engine.js +347 -0
  89. data/engines/rhino/lib/md5-engine.js +40 -0
  90. data/engines/rhino/lib/os-engine.js +150 -0
  91. data/engines/rhino/lib/packages-engine.js +71 -0
  92. data/engines/rhino/lib/sandbox-engine.js +70 -0
  93. data/engines/rhino/lib/system.js +38 -0
  94. data/engines/rhino/lib/worker-engine.js +23 -0
  95. data/engines/rhino/lib/zip.js +78 -0
  96. data/engines/rhino/package.json +4 -0
  97. data/engines/secure/lib/file.js +6 -0
  98. data/engines/secure/lib/system.js +6 -0
  99. data/engines/template/bin/narwhal-engine-name +32 -0
  100. data/engines/template/bootstrap.js +40 -0
  101. data/engines/template/lib/file-engine.js +118 -0
  102. data/engines/template/lib/system.js +17 -0
  103. data/examples/browser-deployment-jackconfig.js +35 -0
  104. data/examples/fibonacci-worker.js +35 -0
  105. data/examples/fibonacci.js +19 -0
  106. data/examples/hello +2 -0
  107. data/examples/narwhal +3 -0
  108. data/examples/not-quite-a-quine.js +1 -0
  109. data/extconf.rb +44 -0
  110. data/gem_bin/narwhal +5 -0
  111. data/gem_bin/sea +4 -0
  112. data/gem_bin/tusk +4 -0
  113. data/lib/args.js +849 -0
  114. data/lib/base16.js +16 -0
  115. data/lib/base64.js +120 -0
  116. data/lib/codec/base64.js +8 -0
  117. data/lib/crc32.js +60 -0
  118. data/lib/file-bootstrap.js +187 -0
  119. data/lib/file.js +659 -0
  120. data/lib/hash.js +28 -0
  121. data/lib/hashp.js +65 -0
  122. data/lib/html.js +16 -0
  123. data/lib/http-client.js +134 -0
  124. data/lib/http.js +17 -0
  125. data/lib/io.js +98 -0
  126. data/lib/jsmin.js +315 -0
  127. data/lib/jsonpath.js +89 -0
  128. data/lib/logger.js +55 -0
  129. data/lib/md4.js +146 -0
  130. data/lib/md5.js +164 -0
  131. data/lib/mime.js +166 -0
  132. data/lib/narwhal.js +102 -0
  133. data/lib/narwhal/client.js +261 -0
  134. data/lib/narwhal/compile.js +99 -0
  135. data/lib/narwhal/env.js +140 -0
  136. data/lib/narwhal/inline.js +106 -0
  137. data/lib/narwhal/json.js +324 -0
  138. data/lib/narwhal/json.md +178 -0
  139. data/lib/narwhal/repl.js +96 -0
  140. data/lib/narwhal/server-test.js +6 -0
  141. data/lib/narwhal/server.js +270 -0
  142. data/lib/narwhal/tusk.js +170 -0
  143. data/lib/narwhal/tusk/bin.js +13 -0
  144. data/lib/narwhal/tusk/bundle.js +0 -0
  145. data/lib/narwhal/tusk/catalog.js +22 -0
  146. data/lib/narwhal/tusk/clone.js +66 -0
  147. data/lib/narwhal/tusk/consolidate.js +25 -0
  148. data/lib/narwhal/tusk/create-catalog.js +80 -0
  149. data/lib/narwhal/tusk/engine.js +42 -0
  150. data/lib/narwhal/tusk/freeze.js +0 -0
  151. data/lib/narwhal/tusk/init.js +56 -0
  152. data/lib/narwhal/tusk/install.js +288 -0
  153. data/lib/narwhal/tusk/list.js +20 -0
  154. data/lib/narwhal/tusk/orphans.js +0 -0
  155. data/lib/narwhal/tusk/reheat.js +15 -0
  156. data/lib/narwhal/tusk/remove.js +15 -0
  157. data/lib/narwhal/tusk/search.js +145 -0
  158. data/lib/narwhal/tusk/update.js +21 -0
  159. data/lib/narwhal/tusk/upgrade.js +0 -0
  160. data/lib/os.js +33 -0
  161. data/lib/packages.js +423 -0
  162. data/lib/printf.js +169 -0
  163. data/lib/promise.js +352 -0
  164. data/lib/querystring.js +176 -0
  165. data/lib/ref-send.js +257 -0
  166. data/lib/regexp.js +12 -0
  167. data/lib/sandbox.js +422 -0
  168. data/lib/sha.js +112 -0
  169. data/lib/sha256.js +102 -0
  170. data/lib/struct.js +228 -0
  171. data/lib/term.js +179 -0
  172. data/lib/test/assert.js +95 -0
  173. data/lib/test/equiv.js +188 -0
  174. data/lib/test/jsdump.js +165 -0
  175. data/lib/test/runner.js +129 -0
  176. data/lib/unload.js +13 -0
  177. data/lib/uri.js +378 -0
  178. data/lib/url.js +5 -0
  179. data/lib/utf8.js +64 -0
  180. data/lib/util.js +985 -0
  181. data/lib/uuid.js +89 -0
  182. data/lib/xregexp.js +521 -0
  183. data/local.json.template +1 -0
  184. data/narwhal.gemspec +105 -0
  185. data/narwhal.js +213 -0
  186. data/package.json +26 -0
  187. data/packages/readline/engines/default/lib/readline.js +4 -0
  188. data/packages/readline/engines/rhino/lib/readline.js +6 -0
  189. data/packages/readline/package.json +5 -0
  190. data/sources.json +207 -0
  191. data/tests/all-tests.js +17 -0
  192. data/tests/args.js +31 -0
  193. data/tests/args/domain.js +215 -0
  194. data/tests/args/options.js +36 -0
  195. data/tests/args/shifting.js +92 -0
  196. data/tests/args/validation.js +31 -0
  197. data/tests/base64.js +23 -0
  198. data/tests/commonjs.js +3 -0
  199. data/tests/commonjs/all-tests.js +12 -0
  200. data/tests/commonjs/bytearray-encodings-tests.js +69 -0
  201. data/tests/commonjs/bytearray-tests.js +465 -0
  202. data/tests/commonjs/bytestring-encodings-tests.js +89 -0
  203. data/tests/commonjs/bytestring-tests.js +263 -0
  204. data/tests/commonjs/es5/all-tests.js +3 -0
  205. data/tests/commonjs/es5/bind.js +29 -0
  206. data/tests/commonjs/file-tests.js +315 -0
  207. data/tests/commonjs/file/dirname.js +31 -0
  208. data/tests/commonjs/file/extension.js +45 -0
  209. data/tests/commonjs/file/is-absolute.js +11 -0
  210. data/tests/commonjs/file/iterator.js +101 -0
  211. data/tests/commonjs/file/normal.js +27 -0
  212. data/tests/commonjs/file/path.js +17 -0
  213. data/tests/commonjs/file/relative.js +42 -0
  214. data/tests/commonjs/file/resolve.js +44 -0
  215. data/tests/commonjs/module-tests.js +9 -0
  216. data/tests/commonjs/modules/absolute/b.js +1 -0
  217. data/tests/commonjs/modules/absolute/program.js +5 -0
  218. data/tests/commonjs/modules/absolute/submodule/a.js +3 -0
  219. data/tests/commonjs/modules/absolute/test.js +9 -0
  220. data/tests/commonjs/modules/all-tests.js +47 -0
  221. data/tests/commonjs/modules/config.js +11 -0
  222. data/tests/commonjs/modules/cyclic/a.js +4 -0
  223. data/tests/commonjs/modules/cyclic/b.js +4 -0
  224. data/tests/commonjs/modules/cyclic/program.js +10 -0
  225. data/tests/commonjs/modules/cyclic/test.js +9 -0
  226. data/tests/commonjs/modules/determinism/program.js +3 -0
  227. data/tests/commonjs/modules/determinism/submodule/a.js +8 -0
  228. data/tests/commonjs/modules/determinism/submodule/b.js +2 -0
  229. data/tests/commonjs/modules/determinism/test.js +9 -0
  230. data/tests/commonjs/modules/exactExports/a.js +3 -0
  231. data/tests/commonjs/modules/exactExports/program.js +4 -0
  232. data/tests/commonjs/modules/exactExports/test.js +9 -0
  233. data/tests/commonjs/modules/hasOwnProperty/hasOwnProperty.js +0 -0
  234. data/tests/commonjs/modules/hasOwnProperty/program.js +3 -0
  235. data/tests/commonjs/modules/hasOwnProperty/test.js +9 -0
  236. data/tests/commonjs/modules/hasOwnProperty/toString.js +0 -0
  237. data/tests/commonjs/modules/method/a.js +12 -0
  238. data/tests/commonjs/modules/method/program.js +8 -0
  239. data/tests/commonjs/modules/method/test.js +9 -0
  240. data/tests/commonjs/modules/missing/program.js +8 -0
  241. data/tests/commonjs/modules/missing/test.js +9 -0
  242. data/tests/commonjs/modules/monkeys/a.js +1 -0
  243. data/tests/commonjs/modules/monkeys/program.js +4 -0
  244. data/tests/commonjs/modules/monkeys/test.js +9 -0
  245. data/tests/commonjs/modules/nested/a/b/c/d.js +3 -0
  246. data/tests/commonjs/modules/nested/program.js +3 -0
  247. data/tests/commonjs/modules/nested/test.js +9 -0
  248. data/tests/commonjs/modules/relative/program.js +5 -0
  249. data/tests/commonjs/modules/relative/submodule/a.js +1 -0
  250. data/tests/commonjs/modules/relative/submodule/b.js +2 -0
  251. data/tests/commonjs/modules/relative/test.js +9 -0
  252. data/tests/commonjs/modules/transitive/a.js +1 -0
  253. data/tests/commonjs/modules/transitive/b.js +1 -0
  254. data/tests/commonjs/modules/transitive/c.js +3 -0
  255. data/tests/commonjs/modules/transitive/program.js +3 -0
  256. data/tests/commonjs/modules/transitive/test.js +9 -0
  257. data/tests/file/all-tests.js +61 -0
  258. data/tests/file/fnmatch.js +102 -0
  259. data/tests/file/glob.js +466 -0
  260. data/tests/file/match.js +102 -0
  261. data/tests/global.js +6 -0
  262. data/tests/global/array.js +19 -0
  263. data/tests/hashes.js +94 -0
  264. data/tests/html.js +13 -0
  265. data/tests/io/stringio.js +21 -0
  266. data/tests/os/all-tests.js +4 -0
  267. data/tests/os/popen.js +41 -0
  268. data/tests/os/system.js +22 -0
  269. data/tests/printf.js +123 -0
  270. data/tests/query-string.js +87 -0
  271. data/tests/sandbox/byte-io.js +20 -0
  272. data/tests/sandbox/fileName.js +3 -0
  273. data/tests/sandbox/foo.js +0 -0
  274. data/tests/sandbox/reload.js +79 -0
  275. data/tests/string.js +35 -0
  276. data/tests/uri.js +41 -0
  277. data/tests/util/all-tests.js +79 -0
  278. data/tests/util/array.js +207 -0
  279. data/tests/util/array/is-arguments.js +29 -0
  280. data/tests/util/array/is-array-like.js +29 -0
  281. data/tests/util/case.js +9 -0
  282. data/tests/util/collection.js +104 -0
  283. data/tests/util/eq.js +57 -0
  284. data/tests/util/expand.js +45 -0
  285. data/tests/util/object.js +125 -0
  286. data/tests/util/operator.js +25 -0
  287. data/tests/util/range.js +19 -0
  288. data/tests/util/repr.js +26 -0
  289. data/tests/util/string.js +34 -0
  290. data/tests/util/unique.js +12 -0
  291. metadata +434 -0
data/docs/download.md ADDED
@@ -0,0 +1,25 @@
1
+
2
+ Narwhal Downloads
3
+ =================
4
+
5
+ Download a version of Narwhal then follow the [quick start guide](http://narwhaljs.org/quick-start.html) to get running!
6
+
7
+ Bleeding Edge
8
+ -------------
9
+
10
+ * [Download zip](http://github.com/tlrobinson/narwhal/zipball/master)
11
+ * [Download tar](http://github.com/tlrobinson/narwhal/tarball/master)
12
+
13
+ * Git: `git clone git://github.com/tlrobinson/narwhal.git`
14
+
15
+ * [View tree](http://github.com/tlrobinson/narwhal/tree/master)
16
+ * [View commit](http://github.com/tlrobinson/narwhal/commit/master)
17
+
18
+
19
+ Releases
20
+ --------
21
+
22
+ <div id="releases-list">Loading...</div>
23
+ <script type="text/javascript" charset="utf-8" src="js/releases.js"></script>
24
+ <script type="text/javascript" charset="utf-8" src="http://github.com/api/v2/json/repos/show/tlrobinson/narwhal/tags?callback=showreleases"></script>
25
+
data/docs/engines.md ADDED
@@ -0,0 +1,32 @@
1
+
2
+ Engines
3
+ =======
4
+
5
+ Narwhal is a standard library and tools for multiple JavaScript engines; each engine has its own library. Use `tusk engine {name}` to select an engine, or edit `narwhal.conf`. The following engines are presently in development:
6
+
7
+ * `rhino`: is the default and most complete engine, based on Mozilla Rhino for Java, used for out-of-the-box functionality.
8
+ * `k7`: is a `v8` based engine, in development by Sébastien Pierre.
9
+ * `helma`: is based on Rhino with extensions, being developed by Hannes Wallnöefer.
10
+ * `xulrunner`: is in development for Firefox extensions and XULRunner applications on the Spidermonkey engine by Irakli Gozalishvili, Christoph Dorn, and Zach Carter.
11
+ * `jaxer`: is an engine based on Mozilla SpiderMonkey, for deploying web pages with both server and client side scripts, being developed by Nathan L Smith.
12
+ * `v8cgi`: is based on the work of Ondrej Zara, and has not been updated in a long while.
13
+ * `default`: is a catchall engine that implements modules that can be shared among engines.
14
+ * `browser`: will eventually be available for client side loading of modules with various techniques.
15
+ * `secure`: will eventually be available for dependency injection sandboxed module systems within some other engines.
16
+
17
+
18
+ Creating new Engine Adapters
19
+ ----------------------------
20
+
21
+ We have a template for new engines at `engines/template` that you can copy to `engines/{name}` and fill in the blanks. These consist of:
22
+
23
+ 1. An executable (shell script or binary) at `engines/{name}/bin/narwhal-{name}` that executes the interpreter engine of choice and causes it to load a bootstrap script. This script will be loaded by `bin/narwhal` with the environment variable `NARWHAL_HOME` set to the Narwhal project directory and `NARWHAL_ENGINE_HOME` set to the engine directory. This script will be run if `NARWHAL_ENGINE` is set to your engine name. You can set `NARWHAL_DEFAULT_ENGINE` or `NARWHAL_ENGINE` in a `narwhal.conf` in your Narwhal project directory (template provided).
24
+
25
+ 2. A "thunk", at `engines/{name}/bootstrap.js` that evaluates `narwhal.js` and passes the returned function a preliminary `system` object with a few required properties (`global`, `evalGlobal`, `engine`, `engines`, `print`, `evaluate`, `prefix`, `fs.read`, and `fs.isFile`). This should be enough to get to an interactive console.
26
+
27
+ 3. Engine implementations for core modules, such as `file` and `system` located in `engines/{name}/lib/`. You can implement `file-engine` instead of `file` if you implement the subset of the ServerJS file API used by `lib/file.js` (and similar for `io`, `os`, `binary`, etc). The next steps are:
28
+
29
+ * system: You must implement `system.args` to be able to pass command line options to Narwhal.
30
+
31
+ * file: To enable the package system you must implement `list`, `canonical`, `mtime`, `isDirectory`, `isFile`.
32
+
data/docs/json-tool.md ADDED
@@ -0,0 +1,121 @@
1
+
2
+ JSON Tool Recipes
3
+ =================
4
+
5
+ List the module search paths:
6
+
7
+ json -e require.paths -np
8
+
9
+ List the package search prefixes:
10
+
11
+ json -e system.prefixes -np
12
+
13
+ List the active engine names:
14
+
15
+ json -e system.engines -np
16
+
17
+ List the prefix paths of every installed package:
18
+
19
+ json -e 'require("packages").order' -n -f directory -p
20
+
21
+ Visit the home page of every contributor to every installed package. "open" is
22
+ on Mac OS X only, but you can use "gnome-open" or "xdg-open" on Linux, or
23
+ "kde-open" on Kubuntu specifically:
24
+
25
+ json -e 'require("packages").order'
26
+ -n
27
+ -e _.contributors
28
+ -A # flatten the array
29
+ -w _.url # if they've got one
30
+ -e _.url # extract it from their Author object
31
+ -p
32
+ | sort | uniq | xargs open
33
+
34
+ List the contributors to Narwhal with field selection:
35
+
36
+ json -i package.json -j -f contributors -Anp
37
+
38
+ Use JSONPath to list the contributors:
39
+
40
+ json -i package.json -j -$ $.contributors -Anp
41
+
42
+ Enquote all of the MP3s in your collection, line by line:
43
+
44
+ find . -name '*.mp3' | json -nJp
45
+
46
+ find . -name '*.mp3' -print0 | json -n0Jp
47
+
48
+ Rename all of your MP3s so that URL encoded patterns are unescaped:
49
+
50
+ find .
51
+ -name '*.mp3'
52
+ -print0 # write null-terminated lines
53
+ | json
54
+ -n # line by line
55
+ -z0 # both read and write null-terminated lines
56
+ -c # this forces an array to
57
+ # be accumulated for reprint
58
+ -p # print in escaped form
59
+ -e 'unescape(_)' -p # reprint unescaped
60
+ | xargs
61
+ -0 # read null-terminated lines
62
+ -n 2 # one command for each adjacent pair
63
+ mv
64
+
65
+ Convert `/etc/passwd` to JSON:
66
+
67
+ json -i /etc/passwd -nd: -NTJp
68
+
69
+ Convert `/etc/passwd` to JSON with Objects instead of Arrays:
70
+
71
+ cat /etc/passwd | json
72
+ -n
73
+ -d:
74
+ -F name,password,uid,gid,class,change,expire,gecos,home,shell
75
+ -x _.uid=+_.uid
76
+ -x _.gid=+_.gid
77
+ -f name,_
78
+ -N
79
+ -O
80
+ -TJp
81
+
82
+ Create a JSON mapping from user name to UID and format it as CSV:
83
+
84
+ cat /etc/passwd | json -nd: -f 0,2 -D, -p
85
+
86
+ Create a JSON mapping from user name to UID and write it out as a single line of JSON:
87
+
88
+ json -i /etc/passwd -nd: -f 0,2 -NOJp
89
+
90
+ Grab the UID of the "root" user:
91
+
92
+ json -i /etc/passwd -nd: -f0,2 -N -O -f root -p
93
+
94
+ Reverse engineer a package catalog from installed packages:
95
+
96
+ json
97
+ -e 'require("packages").order'
98
+ -n # line input mode
99
+ -e '[_.name || _.directory.dirname().basename(), JSON.decode(_.directory.resolve("package.json").read())'
100
+ -N # object input mode
101
+ -O
102
+ -v '{version:1,packages:_}'
103
+ -TJ
104
+ -p
105
+
106
+ Use the JSON tool as a pointless pipe buffer:
107
+
108
+ json -np
109
+
110
+ Print the number '1' thrice.
111
+
112
+ json -e 1 -ppp
113
+
114
+ Find the largest number from 1 to 10:
115
+
116
+ $(which jot) $(which seq) 10 | json -njNe 'Math.max.apply(this, _)' -p
117
+
118
+ Put all your eggs in one basket:
119
+
120
+ json -e 'require("narwhal")' -f LEFT,RIGHT -np
121
+
@@ -0,0 +1,242 @@
1
+ All engines must support two types for interacting with binary data: ByteArray and ByteString. The ByteArray type resembles the interface of Array in that it is mutable, extensible, and indexing will return number values for the byte in the given position, zero by default, or undefined if the index is out of bounds. The ByteString type resembles the interface of String in that it is immutable and indexing returns a ByteString of length 1. These types are exported by the 'binary' top-level module and both types are subtypes of Binary, which is not instantiable but exists only for the convenience of referring to both ByteArray and ByteString. (The idea of using these particular two types and their respective names originated with Jason Orendorff in the [http://groups.google.com/group/serverjs/msg/89808c05d46b92d0 Binary API Brouhaha] discussion.)
2
+
3
+ = Philosophy =
4
+
5
+ This proposal is not an object oriented variation on pack and unpack with notions of inherent endianness, read/write head position, or intrinsic codec or charset information. The objects described in this proposal are merely for the storage and direct manipulation of strings and arrays of byte data. Some object oriented conveniences are made, but the exercise of implementing pack, unpack, or an object-oriented analog thereof are left as an exercise for a future proposal of a more abstract type or a 'struct' module (as mentioned by Ionut Gabriel Stan on [http://groups.google.com/group/serverjs/msg/592442ba98c6c70e the list]). This goes against most mentioned [[ServerJS/Binary|prior art]].
6
+
7
+ This proposal also does not provide named member functions for any particular subset of the possible charsets, codecs, compression algorithms, or consistent hash digests that might operate on a byte string or array. Instead, convenience member functions are provided for interfacing with any named charset, with the IANA charset name space, and with the possibility of eventually employing a system of modular extensions for other codecs or digests, requiring that the given module exports a specified interface. (As supported originally by Robert Schultz, Davey Waterson, Ross Boucher, and tacitly myself, Kris Kowal, on the [http://groups.google.com/group/serverjs/browse_thread/thread/be72ef3d8146731d/06c27162b698eef5?lnk=gst First proposition] thread on the mailing list). This proposal does not address the need for stream objects to support pipelined codecs and hash digests (mentioned by Tom Robinson and Robert Schultz in the same conversation).
8
+
9
+ This proposal also reflects both group sentiment and a pragmatic point about properties. This isn't a decree that properties like "length" should be consistently used throughout the ServerJS APIs. However, given that all engines support properties at the native level (to host String and Array objects) and that byte strings and arrays will require support at the native level, pursuing client-side interoperability is beyond the scope of this proposal and therefore properties have been specified. (See comments by Kris Zyp about the implementability of properties in all engines, comments by Davey Waterson from Aptana about the counter-productivity of attempting to support this API in browsers, and support properties over accessor and mutator functions by Ionut Gabriel Stand and Cameron McCormack on the [http://groups.google.com/group/serverjs/browse_thread/thread/be72ef3d8146731d/06c27162b698eef5?lnk=gst mailing list]).
10
+
11
+ The byte types provide functions for encoding, decoding, and transcoding, but they are all shallow interfaces that defer to a charset manager module, and may in turn use a system level charset or use a pair of pure JavaScript modules to transcode through an array or stream of canonical Unicode code points. This behavior may be specified further in the future.
12
+
13
+ = Specification =
14
+
15
+ The "binary" top-level module must export "Binary", "ByteArray" and "ByteString".
16
+
17
+
18
+ == ByteString ==
19
+
20
+ A ByteString is an immutable, fixed-width representation of a C unsigned char (byte) array. ByteString supports the String API, and indexing returns a byte substring of length 1.
21
+
22
+ === Constructor ===
23
+
24
+ ; ByteString()
25
+ : Construct an empty byte string.
26
+ ; ByteString(byteString)
27
+ : Copies byteString.
28
+ ; ByteString(byteArray)
29
+ : Use the contents of byteArray.
30
+ ; ByteString(arrayOfNumbers)
31
+ : Use the numbers in arrayOfNumbers as the bytes.
32
+ : If any element is outside the range 0...255, an exception (''TODO'') is thrown.
33
+ ; ByteString(string, charset)
34
+ : Convert a string. The ByteString will contain string encoded with charset.
35
+
36
+ === Constructor methods ===
37
+
38
+ ; join(array, delimiter)
39
+ : Like Array.prototype.join, but for Binarys. Returns a ByteString.
40
+
41
+ === Instance properties ===
42
+
43
+ ; length
44
+ : The length in bytes. Immutable.
45
+
46
+ === Instance methods (in prototype) ===
47
+
48
+ ; toByteArray()
49
+ : Returns a byte for byte copy in a ByteArray.
50
+ ; toByteArray(sourceCharset, targetCharset)
51
+ : Returns a transcoded copy in a ByteArray.
52
+ ; toByteString()
53
+ : Returns itself, since there's no need to copy an immutable ByteString.
54
+ ; toByteString(sourceCharset, targetCharset)
55
+ : Returns a transcoded copy.
56
+ ; toArray()
57
+ : Returns an array containing the bytes as numbers.
58
+ ; toArray(charset)
59
+ : Returns an array containing the decoded Unicode code points.
60
+ ; toString()
61
+ : Returns a debug representation like "[ByteString 10]", where 10 is the length of the Array. Alternative debug representations are valid too, as long as (1) this method will never fail, (2) the length is included.
62
+ ; decodeToString(charset)
63
+ : Returns the decoded ByteArray as a string.
64
+ ; indexOf(byte)
65
+ ; indexOf(byte, start)
66
+ ; indexOf(byte, start, stop)
67
+ : Returns the index of the first occurance of byte (a Number or a single element ByteString or ByteArray) or -1 if none was found. If start and/or stop are specified, only elements between the the indexes start and stop are searched.
68
+ ; lastIndexOf(byte)
69
+ ; lastIndexOf(byte, start)
70
+ ; lastIndexOf(byte, start, stop)
71
+ : Returns the index of the last occurance of byte (a Number or a single element ByteString or ByteArray) or -1 if none was found. If start and/or stop are specified, only elements between the the indexes start and stop are searched.
72
+ ; charCodeAt(offset)
73
+ ; <u>get(offset)</u>
74
+ : Return the byte at offset as a Number.
75
+ ; byteAt(offset) ByteString
76
+ ; charAt(offset) ByteString
77
+ : Return the byte at offset as a ByteString.
78
+ ; split(delimiter, [options])
79
+ : Split at delimiter, which can by a Number, a ByteString, a ByteArray or an Array of the prior (containing multiple delimiters, i.e., "split at any of these delimiters"). Delimiters can have arbitrary size.
80
+ : Options is an optional object parameter with the following optional properties:
81
+ * ''count'' - Maximum number of elements (ignoring delimiters) to return. The last returned element may contain delimiters.
82
+ * ''includeDelimiter'' - Whether the delimiter should be included in the result.
83
+ : Returns an array of ByteStrings.
84
+ ; slice()
85
+ ; slice(begin)
86
+ ; slice(begin, end)
87
+ : See [https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/slice Array.prototype.slice]
88
+
89
+
90
+ ; substr(start)
91
+ :
92
+ ; substr(start, length)
93
+ :
94
+ ; substring(first)
95
+ :
96
+ ; substring(first, last)
97
+
98
+ ; [] ByteString
99
+ : the immutable [] operator returning ByteStrings
100
+ ; toSource()
101
+ : which would return "ByteString([])" for a null byte string
102
+
103
+ ByteString does not implement toUpperCase() or toLowerCase() since they are not meaningful without the context of a charset.
104
+
105
+ == ByteArray ==
106
+
107
+ A ByteArray is a mutable, flexible representation of a C unsigned char (byte) array.
108
+
109
+ === Constructor ===
110
+
111
+ ; ByteArray()
112
+ : New, empty ByteArray.
113
+ ; ByteArray(length)
114
+ : New ByteArray filled with length zero bytes.
115
+ ; ByteArray(byteArray)
116
+ : Copy byteArray.
117
+ ; ByteArray(byteString)
118
+ : Copy contents of byteString.
119
+ ; ByteArray(arrayOfBytes)
120
+ : Use numbers in arrayOfBytes as contents.
121
+ : Throws an exception if any element is outside the range 0...255 (''TODO'').
122
+ ; ByteArray(string, charset)
123
+ : Create a ByteArray from a Javascript string, the result being encoded with charset.
124
+
125
+ Unlike the Array, the ByteArray is not variadic so that its initial length constructor is not ambiguous with its copy constructor.
126
+
127
+ All values within the length of the array are numbers stored as bytes that default to 0 if they have not been explicitly set. Assigning beyond the bounds of a ByteArray implicitly grows the array, just like an Array. Retrieving a value from an index that is out of the bounds of the Array, lower than 0 or at or beyond the length, the returned value is "undefined". Assigning an index with a value that is larger than fits in a byte will be implicitly and silently masked against 0xFF. Negative numbers will be bit extended to a byte in two's complement form and likewise masked.
128
+
129
+ === Instance properties ===
130
+
131
+ ; mutable length property
132
+ : extending a byte array fills the new entries with 0.
133
+
134
+ === Instance methods (in prototype) ===
135
+
136
+ ; toArray()
137
+ : n array of the byte values
138
+ ; toArray(charset)
139
+ : an array of the code points, decoded
140
+ ; toString()
141
+ : A string debug representation like "[ByteArray 10]". Alternative debug representations are valid too, as long as (1) this method will never fail, (2) the length is included.
142
+ ; decodeToString(charset)
143
+ : returns a String from its decoded bytes in a given charset.
144
+ ; toByteArray()
145
+ : just a copy
146
+ ; toByteArray(sourceCharset, targetCharset)
147
+ : transcoded
148
+ ; toByteString()
149
+ : byte for byte copy
150
+ ; toByteString(sourceCharset, targetCharset)
151
+ : transcoded
152
+ ; <u>byteAt(offset) ByteString</u>
153
+ : Return the byte at offset as a ByteString.
154
+ ; <u>get(offset) Number</u>
155
+ : Return the byte at offset as a Number.
156
+ ; concat(other:ByteArray|ByteString|Array)
157
+ ; pop() byte:Number
158
+ :
159
+ ; push(...variadic Numbers...) -> count(Number)
160
+ :
161
+ ; <u>extendRight(...variadic Numbers / Arrays / ByteArrays / ByteStrings ...)</u>
162
+ :
163
+ ; shift() byte:Number
164
+ :
165
+ ; unshift(...variadic Numbers...) count:Number
166
+ :
167
+ ; <u>extendLeft(...variadic Numbers / Arrays / ByteArrays / ByteStrings ...)</u>
168
+ :
169
+ ; reverse() in place reversal
170
+ :
171
+ ; slice()
172
+ :
173
+ ; sort()
174
+ :
175
+ ; splice()
176
+ :
177
+ ; <u>indexOf()</u>
178
+ :
179
+ ; <u>lastIndexOf()</u>
180
+ :
181
+ ; <u>split()</u>
182
+ : Returns an array of ByteArrays instead of ByteStrings.
183
+ ; <u>filter()</u>
184
+ :
185
+ ; <u>forEach()</u>
186
+ :
187
+ ; <u>every()</u>
188
+ :
189
+ ; <u>some()</u>
190
+ :
191
+ ; <u>map()</u>
192
+ :
193
+ ; <u>reduce()</u>
194
+ :
195
+ ; <u>reduceRight()</u>
196
+ :
197
+ ; <u>displace(begin, end, values/ByteStrings/ByteArrays/Arrays...) -> length</u>
198
+ : begin/end are specified like for slice. Can be used like splice but does not return the removed elements.
199
+ ; toSource()
200
+ : Returns a string like "ByteArray([])" for a null byte-array.
201
+ ; [] Number
202
+ : The mutable [] operator for numbers
203
+
204
+ == String ==
205
+
206
+ The String prototype will be extended with the following members:
207
+
208
+ ; toByteArray(charset)
209
+ : Converts a string to a ByteArray encoded in charset.
210
+ ; toByteString(charset)
211
+ : Converts a string to a ByteString encoded in charset.
212
+ ; charCodes()
213
+ : Returns an array of Unicode code points (as numbers).
214
+
215
+ == Array ==
216
+
217
+ The Array prototype will be extended with the following members:
218
+
219
+ ; toByteArray(charset)
220
+ : Converts an array of Unicode code points to a ByteArray encoded in charset.
221
+ ; toByteString(charset)
222
+ : Converts an array of Unicode code points to a ByteString encoded in charset.
223
+
224
+ == General Requirements ==
225
+
226
+ None of the specified prototypes or augmentations to existing prototypes are enumerable.
227
+
228
+ <u>Any operation that requires encoding, decoding, or transcoding among charsets may throw an error if that charset is not supported by the implementation. All implementations MUST support "us-ascii" and "utf-8".</u>
229
+
230
+ Charset strings are as defined by IANA http://www.iana.org/assignments/character-sets.
231
+
232
+ <u>Charsets are case insensitive.</u>
233
+
234
+ = Tests =
235
+
236
+ * [http://github.com/tlrobinson/narwhal/tree/master/tests/serverjs ServerJS tests] compatible with [http://github.com/tlrobinson/narwhal/tree/master/lib/test this test framework].
237
+
238
+ = Relevant Discussions =
239
+
240
+ * [http://groups.google.com/group/serverjs/browse_thread/thread/f8ad81201f7b121b ByteArray and ByteString proposal]
241
+ * [http://groups.google.com/group/serverjs/browse_thread/thread/a8d3a91af37fd355 ByteArray: byteAt method]
242
+ * [http://groups.google.com/group/serverjs/browse_thread/thread/45190ac89d7b422a Binary/B Extension Proposals and Implementation Notes]
@@ -0,0 +1,325 @@
1
+ Proposal A, Draft 5 (in development)
2
+
3
+ The "file" module supports the File System API, providing an interface for path, directory, file, link, file stat, and file stream manipulation.
4
+
5
+ For the purpose of this documentation, "fs" is a variable name for any object that implements the File System API, including the exports of the "file" module, and objects returned by "fs.chroot(path)".
6
+
7
+
8
+ === Security ===
9
+
10
+ Objects implementing the File System API, including the "file" module object, are capability bearing objects that carry and mediate authority to read and write to the underlying storage. As such, the "file" module can return other objects that implement and attenuate the File System API for sandboxing. Furthermore, streams returned by the file system object are implicitly attenuated to only give the receiver authority to manipulate the given file, without knowledge of the path on which it resides or access to references that would permit it to manipulate other parts of the file system.
11
+
12
+
13
+ === Interface ===
14
+
15
+ The "file" module must export the following:
16
+
17
+ ==== Files ====
18
+
19
+ ; open(path String, mode|options)
20
+ : returns a stream object that supports an appropriate interface for the given options and mode, which include reading, writing, updating, byte, character, unbuffered, buffered, and line buffered streams. More details follow in the [#Stream] section of this document.
21
+ * path
22
+ * mode: "rwa+bxc", or
23
+ * options
24
+ ** mode String
25
+ ** charset String
26
+ ** read Boolean
27
+ ** write Boolean
28
+ ** append Boolean
29
+ ** update Boolean
30
+ ** binary Boolean
31
+ ** exclusive Boolean
32
+ ** canonical Boolean
33
+ ; read(path String, [mode|options])
34
+ : opens, reads, and closes a file, returning its content.
35
+ ; write(path String, content String|Binary, [mode|options])
36
+ : opens, writes, flushes, and closes a file with the given content. If the content is a ByteArray or ByteString, the binary mode is implied.
37
+ ; copy(source String, target String)
38
+ : reads one file and writes another in byte mode.
39
+ ; move(from String, to String)
40
+ :
41
+ ; remove(path String)
42
+ :
43
+ ; rename(path String, name String)
44
+ :
45
+ ; touch(path, [mtime Date])
46
+ :
47
+
48
+ ==== Directories ====
49
+
50
+ ('''TODO''' Should the methods in this section use "mkdir" or "makeDir" style names? [http://groups.google.com/group/serverjs/browse_thread/thread/851fea66620bae13 discussion])
51
+
52
+ ; list(path String) Iterator
53
+ : returns an iterator that yields the names of the entries in a directory. Throws an error if the directory is inaccessible or does not exist.
54
+ ; mkdir(path String)
55
+ : Create a single directory specified by ''path''. If the directory cannot be created for any reason an exception will be thrown. This includes if the parent directories of "path" are not present.
56
+ :
57
+ ; mktree(path String)
58
+ : '''TODO''' Decide upon the name of this function. "mkdirs" or "mktree" or "makeTree"
59
+ : Will create the directory specified by "path" including any missing parent directories.
60
+ :
61
+ ; rmdir(path String)
62
+ : Removes a directory if it is empty. If it is not, or cannot be removed for another reason an exception will be thrown.
63
+ :
64
+ ; rmtree(path String)
65
+ :
66
+ : This does its best to remove the directory "path", akin to "rm -r" on Unix or "del /s" on Windows. That is it will recursively delete all directories and files under "path".
67
+
68
+ ==== Links ====
69
+
70
+ ==== Paths ====
71
+
72
+ ; [new] Path(path String|Path|Array, [fs FileSystem]) Path
73
+ : returns a Path object that closes on a File System object and a "path" representation. The path object is a chainable shorthand for working with paths in the context of the "file" module. "Path" objects have no more or less authority to manipulate the file system than the FileSystem object that they are attached to, as any path string is reachable by chaining operations on a path instance. The FileSystem object defaults to the "file" module if the argument is omitted or undefined. More details follow in the [#Path Path] section of this document.
74
+ ; path(path String|Path, fs FileSystem) Path
75
+ : "fs.path(path)" is a shorthand for "new fs.Path(path, fs)".
76
+
77
+ ===== Working Path =====
78
+
79
+ The current working directory is used by all routines that resolve relative paths to absolute file system paths, including "open", and "absolute".
80
+
81
+ ; cwd() String
82
+ : returns the current working directory.
83
+ ; chdir(path String)
84
+ : changes the current working directory.
85
+
86
+ ===== Traditional =====
87
+
88
+ ; join(...)
89
+ : takes a variadic list of path Strings, joins them on the file system's path separator, and normalizes the result.
90
+ ; split(path String) Array
91
+ : returns an array of path components. If the path is absolute, the first component will be an indicator of the root of the file system; for file systems with drives (such as Windows), this is the drive identifier with a colon, like "c:"; on Unix, this is an empty string "". The intent is that calling "join.apply" with the result of "split" as arguments will reconstruct the path.
92
+ ; normal(path String)
93
+ : removes '.' path components and simplifies '..' paths, if possible, for a given path.
94
+ ; absolute(path String)
95
+ : returns the absolute path, starting with the root of this file system object, for the given path, resolved from the current working directory. If the file system supports home directory aliases, absolute resolves those from the root of the file system. The resulting path is in normal form. On most systems, this is equivalent to expanding any user directory alias, joining the path to the current working directory, and normalizing the result. "absolute" can be implemented in terms of "cwd", "join", and "normal".
96
+ ; canonical(path String)
97
+ : returns the canonical path to a given abstract path. Canonical paths are both absolute and intrinsic, such that all paths that refer to a given file (whether it exists or not) have the same corresponding canonical path. This function must not communicate information about the true parent directories of files in chroot environments. This function is equivalent to expanding a user directory alias, joining the given path to the current working directory, joining all symbolic links along the path, and normalizing the result. "canonical" can be implemented in terms of "cwd", "join", "normal" and "readlink".
98
+ ; dirname(path String) String
99
+ : returns the path of a file's containing directory, albeit the parent directory if the file is a directory. A terminal directory separator is ignored.
100
+ ; basename(path String, [extension String]) String
101
+ : returns the part of the path that is after the last directory separator. If an extension is provided and is equal to the file's extension, the extension is removed from the result.
102
+ ; extension(path String) String
103
+ : returns the extension of a file. The extension of a file is the last dot (excluding any number of initial dots) followed by one or more non-dot characters. Returns an empty string if no valid extension exists. [http://github.com/kriskowal/narwhal-test/blob/master/src/test/file/extension.js unit test].
104
+
105
+ ===== URL-like =====
106
+
107
+ ; resolve(...)
108
+ : a function like "join" except that it treats each argument as as either an absolute or relative path and, as is the convention with URL's, treats everything up to the final directory separator as a location, and everything afterward as an entry in that directory, even if the entry refers to a directory in the underlying storage. Resolve starts at the location "" and walks to the locations referenced by each path, and returns the path of the last file. Thus, resolve(file, "") idempotently refers to the location containing a file or directory entry, and resolve(file, neighbor) always gives the path of a file in the same directory. "resolve" is useful for finding paths in the "neighborhood" of a given file, while gracefully accepting both absolute and relative paths at each stage. [http://github.com/kriskowal/narwhal-test/blob/master/src/test/file/resolve.js unit test].
109
+ ; relative(from, to)
110
+ : returns the relative path from one path to another using only ".." to traverse up to the two paths' common ancestor.
111
+
112
+ ==== Tests ====
113
+
114
+ ; exists(path)
115
+ :whether a file exists at a given path: receives a path and returns whether that path, joined on the current working directory, corresponds to a file that exists. If the file is a broken symbolic link, returns false.
116
+ ; isFile(path)
117
+ :returns whether a path exists and that it corresponds to a file.
118
+ ; isDirectory(path)
119
+ :returns whether a path exists and that it corresponds to a directory.
120
+ ; isLink(path)
121
+ :returns whether a path exists and that it corresponds to a symbolic link (TODO or shortcut?).
122
+ ; isReadable(path)
123
+ :returns whether a path exists, that it corresponds to a file, and that it can be opened for reading by "fs.open".
124
+ ; isWritable(path)
125
+ :If a path exists, returns whether a file may be opened for writing, or entries added or removed from an existing directory. If the path does not exist, returns whether entries for files, directories, or links can be created at its location.
126
+
127
+ ==== Metadata ====
128
+
129
+ ; stat(path String)
130
+ :Returns an object that contains the file's metadata, including all of the following that are applicable in the target platform's file system
131
+ ;; device Number
132
+ :device number of the file system
133
+ ;; inode Number
134
+ :virtual node number
135
+ ;; mode Number
136
+ :type and permissions, numeric
137
+ ;; linkCount Number
138
+ :number of hard links to the file
139
+ ;; uid Number
140
+ :numeric id of the owner user
141
+ ;; rdev Number
142
+ :the device identifier for special files
143
+ ;; size Number
144
+ :total size in bytes
145
+ ;; blockSize Number
146
+ :preferred block size for file system IO, in bytes
147
+ ;; blockCount Number
148
+ :number of blocks allocated
149
+ ;; mtime Date
150
+ :time of last modification (write)
151
+ ;; atime Date
152
+ :time of last access (read, write, update)
153
+ ;; ctime Date
154
+ :(TODO created vs. stat changed. is /.time/ really the best pattern for expressing these times?)
155
+ ;; xattrs
156
+ :extended attributes (reserved)
157
+ ;; acls
158
+ :access control lists (reserved)
159
+
160
+ ; size(path String)
161
+ :Number
162
+ ; mtime(path String)
163
+ :Date
164
+ ; atime(path String)
165
+ :Date
166
+ ; ctime(path String)
167
+ :Date
168
+ ; same(pathA String, pathB String) Boolean
169
+ :whether the two files are identical, in that they come from the same file system, same device, and have the same node and corresponding storage, such that modifying one would implicitly and atomically modify the other.
170
+
171
+ ==== Security ====
172
+
173
+ ; chroot(path String)
174
+ : returns an object that conforms to the File System API, like the "file" module or the "system.fs" variable, that can be safely passed into a sandbox as the "file" module and "system.fs" objects.
175
+
176
+
177
+ == Path ==
178
+
179
+ ; [new] Path(path String|Path|Array, [fs FileSystem]) Path
180
+ :
181
+
182
+ The prototype for the Path constructor is a String object.
183
+
184
+ The path constructor accepts as its first argument either a String, Path, or Array. If the path is an Array (as tested by Array.isArray, not merely typeof path == "array"), it must conform to the specification for values returned by "fs.split".
185
+
186
+ Every path object has the members "normal", "absolute", "canonical", "dirname", "basename", "join", and "resolve". All of these return new Path objects constructed by converting the path to a string, passing it through the likewise named method of "fs", and converting it back to a Path. Thus, all of these methods are chainable. In addition, "join" and "resolve" are variadic, so additional paths can be passed as arguments in either String, Path, or Array form.
187
+
188
+ Every path object has "chroot", "copy", "exists", "extension", "isDirectory", "isFile", "isLink", "isReadable", "isWritable", "mkdir", "mkdirs", "move", "mtime", "open", "read", "remove", "rename", "rmdir", "rmtree", "same", "size", "split", "stat", "touch", and "write". All of these functions convert themselves to strings and pass the results through the likewise named method of "fs".
189
+
190
+ In addition, paths implement:
191
+
192
+ ; toString()
193
+ :
194
+ ; to(path)
195
+ : uses "fs.relative" to return a Path from this path to another one.
196
+ ; from(path)
197
+ : uses "fs.relative" to return a Path to this path from another one.
198
+ ; list()
199
+ : returns an iterator of Path objects for the contained directory entries.
200
+
201
+ (TODO resolve whether it's more proper to make "Path" foundational and eliminate "fs". Wrapping the "Path" object around a central "fs" object will be necessary for "chroot" whether we expose that level of the API or not, and having routines that work with strings on one architectural layer and paths on the next up gives the programmer an oppoertunity to program at the level that makes sense for their task. It also, however, gives the programmer more to learn.)
202
+
203
+
204
+ == Streams ==
205
+
206
+ The "open" function mediates the construction of various kinds of streams. As "open" is the only method with the authority to manipulate files, it constructs these types on behalf of a potentially unpriviledged caller. Stream constructors are not directly callable in a secure sandbox, so where and how these stream types are implemented is beyond the necessary scope of this specification. The "open" function always creates a byte level stream, and by default wraps that in a textual IO wrapper.
207
+
208
+ * create a "raw" byte stream. If "x" mode (with either "w" or "a" mode), only open if the file does not already exist. Create the file and open the stream atomically.
209
+ ** if "r" mode, make "raw" a ByteReader
210
+ ** if "w" mode, make "raw" a ByteWriter
211
+ ** if "u" mode, make "raw" a ByteUpdater
212
+ * if "+", seek to end.
213
+ * if not "b" mode, return "raw".
214
+ * return a wrapper encoded/decoded string stream around "raw" with specified buffering, line buffering, and charset.
215
+ ** if "r" mode, wrap "raw" in a TextReader
216
+ ** if "w" mode, wrap "raw" in a TextWriter
217
+ ** if "u" mode, wrap "raw" in a TextUpdater
218
+
219
+ ; ByteReader
220
+ : appropriate for reading binary opaque struct records or other binary data or protocols
221
+ ; ByteWriter
222
+ : appropriate for writing binary opaque struct records or other binary data or protocols
223
+ ; ByteUpdater
224
+ : appropriate for a database
225
+ ; ByteReaderWriter
226
+ : appropriate for sockets
227
+ ; TextReader
228
+ : appropriate for standard input
229
+ ; TextWriter
230
+ : appropriate for standard output
231
+ ; TextUpdater
232
+ :
233
+ ; TextReaderWriter
234
+ : appropriate for a TTY
235
+
236
+ (TODO: resolve whether it is necessary for all stream types to have a common prototype, or whether it makes sense for them to be arranged in a class hierarchy.)
237
+
238
+ === *Reader, *Updater ===
239
+
240
+ TextReader, ByteReader, TextUpdater, ByteUpdater, TextReaderWriter, and ByteReaderWriter have the following properties and methods:
241
+
242
+ ; read() *String
243
+ : reads and returns all of the file until EOF is encountered. Return ByteStrings for Byte* types, and Strings for Text* types.
244
+ ; read(max Number) *String
245
+ :
246
+ ; readInto(buffer *Array, [begin Number], [end Number]) Number
247
+ :
248
+ ; canRead() Boolean
249
+ :
250
+ ; skip(n Number) Number
251
+ :
252
+
253
+ === *Writer, *Updater ===
254
+
255
+ TextWriter, ByteWriter, TextUpdater, ByteUpdater, TextReaderWriter, and ByteReaderWriter have the following properties and methods:
256
+
257
+ ; canWrite() Boolean
258
+ :
259
+ ; flush()
260
+ :
261
+
262
+ === ByteUpdater ===
263
+
264
+ ; tell() Number
265
+ :
266
+ ; seek(position Number, whence Number)
267
+ :
268
+ ; truncate([length Number=0])
269
+ :
270
+ ; rewind()
271
+ : a shortcut for seek(0)
272
+
273
+ === Text* ===
274
+
275
+ TextReader, TextWriter, TextUpdater, and TextReaderWriter have the following properties and methods:
276
+
277
+ ; raw Byte*
278
+ : the underlying byte stream, ByteReader for TextReaders, ByteWriter for TextWriters, and so on.
279
+
280
+ === TextReader ===
281
+
282
+ ; readLine() String
283
+ : reads a line from the reader. If EOF is encountered before any data is gathered, returns "". Otherwise, returns the line including the "newLine".
284
+ ; readLines() Array*String
285
+ : returns an Array of Strings accumulated by calling readLine until an empty string turns up. Does not include the final empty string, and does include "newLine" at the end of every line.
286
+ ; next() String or throws StopIteration
287
+ : returns the next line of input without its "newLine". Throws StopIteration if EOF is encountered.
288
+ ; iterator() Iterator
289
+ : returns the reader itself
290
+
291
+ === TextWriter ===
292
+
293
+ ; writeLine(line String)
294
+ :
295
+ ; print(...)
296
+ : writes a "delimiter" delimited array of Strings terminated with a "newLine"
297
+
298
+ === TextUpdater ===
299
+
300
+ ; tell() OpaqueCookie
301
+ :
302
+ ; seek(position OpaqueCookie)
303
+ :
304
+ ; truncate([position OpaqueCookie)
305
+ :
306
+ ; rewind()
307
+ : seeks to the beginning of the file.
308
+
309
+
310
+ == Notes ==
311
+
312
+ * Path separators, and other file-system-specific constants are not included in this specification.
313
+
314
+ = Todo =
315
+
316
+ * <s>random access IO</s>
317
+ * locks
318
+ * <s>canonical IO (non-blocking)</s>
319
+ * comprehensive stat <s>access</s> and modification
320
+ * temporary files and directories
321
+ * symbolic links
322
+ * more open options: permissions, owner, groupOwner
323
+ * copy with metadata
324
+ * glob
325
+ * other [https://wiki.mozilla.org/ServerJS/API/file/Names proposed names].