yhara-tickets 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,20 @@
1
+ = tickets
2
+
3
+ Two-dimentional TODO manager.
4
+
5
+ == Install
6
+
7
+ gem install ramaze sequel sqlite3-ruby
8
+ gem install yhara-tickets
9
+
10
+ == Execute
11
+
12
+ tickets-server
13
+
14
+ then open http://localhost:7007/ in your browser.
15
+
16
+ in default, ~/.tickets.db is created to save tickets data.
17
+
18
+ == Configuration
19
+
20
+ write ~/.tickets.conf (see dot.tickets.conf.sample)
data/TODO ADDED
@@ -0,0 +1,61 @@
1
+ = before 1.x.x
2
+
3
+ - write server tests
4
+ - write client tests
5
+ - when origin is clicked
6
+ - new ticket appears on the filed
7
+ - request: /tickets/create
8
+ - when a ticket is clicked
9
+ - ticket info is shown in the hand
10
+ - when a ticket is moved
11
+ - request: /tickets/move? id, x, y
12
+ - when ticket title is cliced
13
+ - show ticket form
14
+ - when ok is clicked
15
+ - show new title in the hand
16
+ - show new title in the field
17
+ - request: /tickets/rename? id, new
18
+ - when delete button is clicked
19
+ - ask really delete the ticket
20
+ - when Y is clicked
21
+ - remove the ticket from the field
22
+ - clear the hand
23
+ - request: /tickets/delete? id
24
+ - when N is clicked
25
+ - do not remove the ticket from the field
26
+ - keep the hand
27
+ - no request
28
+
29
+ - refactor scheme code (use hashtable as object)
30
+
31
+ = before 0.4.0
32
+
33
+ - change orm to datamapper(or ActiveRecord?)
34
+ - implement tags
35
+ - different color
36
+ - show certain tag only
37
+ - tag 'Done' means fixed tags
38
+
39
+ = before 0.3.0
40
+
41
+ - memorize date when a ticket is created
42
+ - memorize date when a ticket is deleted
43
+
44
+ = before 0.2.0
45
+
46
+ - add Tickets::VERSION?
47
+ - edit ticket body
48
+
49
+ = before 0.1.0
50
+
51
+ + fix ticket positions (center=0,0)
52
+ + show deleted tickets (including timeouted ones)
53
+ + automatically move tickets
54
+
55
+ + Make it installable :-)
56
+ + write gemspec (with rtask)
57
+ + dependency (ramaze)
58
+ + automatic migration in start.rb
59
+ + save database on ~/.tickets.db
60
+ + move executable to bin/
61
+ + command line option (port, db)
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'ramaze'
4
+ require 'ramaze/setup'
5
+
6
+ # load config
7
+ conf_path = File.expand_path("~/.tickets.conf")
8
+ load conf_path if File.exist?(conf_path)
9
+
10
+ # update config
11
+ module Tickets
12
+ module Config
13
+ DB_PATH = File.expand_path("~/.tickets.db") unless defined?(DB_PATH)
14
+ PORT = 7007 unless defined?(PORT)
15
+
16
+ SHAKE_INTERVAL = 24 # hours
17
+ SHAKE_DISTANCE = 8 # pixels
18
+
19
+ BOARD_WIDTH = 600 # pixels
20
+ BOARD_HEIGHT = 600 # pixels
21
+ end
22
+ end
23
+
24
+ # connect database
25
+ $LOAD_PATH.unshift(File.expand_path("../", File.dirname(__FILE__)))
26
+ require 'model/ticket'
27
+
28
+ # controllers
29
+ class MainController < Ramaze::Controller
30
+ def index
31
+ Ticket.shake! if Ticket.needs_shaking?
32
+ end
33
+
34
+ def track
35
+ @tickets = Ticket.filter(:deleted => true).reverse_order(:id)
36
+ end
37
+ end
38
+
39
+ class ConfigController < Ramaze::Controller
40
+ map '/config'
41
+ deny_layout :all
42
+
43
+ def board_size
44
+ "(xy . (#{Tickets::Config::BOARD_WIDTH} . #{Tickets::Config::BOARD_HEIGHT}))"
45
+ end
46
+ end
47
+
48
+ class TicktesController < Ramaze::Controller
49
+ map '/tickets'
50
+ deny_layout :all
51
+
52
+ def create
53
+ ticket = Ticket.new
54
+ ticket.save
55
+
56
+ "(id . #{ticket.id})"
57
+ end
58
+
59
+ def list
60
+ tickets = Ticket.filter(:deleted => false).all
61
+
62
+ '(' +
63
+ tickets.map{|ticket|
64
+ "(#{ticket.id} #{ticket.title.inspect} #{ticket.emergency} #{ticket.importance})"
65
+ }.join(' ') +
66
+ ')'
67
+ end
68
+
69
+ def move
70
+ raise "must be via POST" unless request.post?
71
+ ticket = Ticket.find(:id => request["id"])
72
+ raise "ticket not found" unless ticket
73
+
74
+ ticket.update(:emergency => request["x"],
75
+ :importance => request["y"])
76
+ "#t"
77
+ end
78
+
79
+ def rename
80
+ raise "must be via POST" unless request.post?
81
+ ticket = Ticket.find(:id => request["id"])
82
+ raise "ticket not found" unless ticket
83
+
84
+ ticket.update(:title => request["title"])
85
+ "#t"
86
+ end
87
+
88
+ def delete
89
+ raise "must be via POST" unless request.post?
90
+ ticket = Ticket.find(:id => request["id"])
91
+ raise "ticket not found" unless ticket
92
+
93
+ ticket.update(:deleted => true)
94
+ "#t"
95
+ end
96
+ end
97
+
98
+ Ramaze.setup do
99
+ option.port = Tickets::Config::PORT
100
+ end
101
+ Ramaze.start
@@ -0,0 +1,14 @@
1
+ class CreateTickets < Sequel::Migration
2
+ def up
3
+ create_table :tickets do
4
+ primary_key :id
5
+ integer :importance, :null => false, :default => 0
6
+ integer :emergency, :null => false, :default => 0
7
+ string :title, :null => false, :default => ""
8
+ end
9
+ end
10
+
11
+ def down
12
+ drop_table :tickets
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ class AddDeletedToTickets < Sequel::Migration
2
+ def up
3
+ alter_table :tickets do
4
+ add_column :deleted, :boolean, :null => false, :default => false
5
+ end
6
+ end
7
+
8
+ def down
9
+ alter_table :tickets do
10
+ drop_column :deleted
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class AddTimeoutedToTickets < Sequel::Migration
2
+ def up
3
+ alter_table :tickets do
4
+ add_column :timeouted, :boolean, :null => false, :default => false
5
+ end
6
+ end
7
+
8
+ def down
9
+ alter_table :tickets do
10
+ drop_column :timeouted
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ #
2
+ # ~/.tickets.conf example
3
+ #
4
+ module Tickets
5
+ module Config
6
+ DB_PATH = File.expand_path("~/data/.tickets.db")
7
+ PORT = 7000
8
+ end
9
+ end
data/model/ticket.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'sequel'
2
+ require 'sequel/extensions/migration'
3
+ Sequel::Model.plugin(:schema) # for table_exists?
4
+
5
+ $db = Sequel.sqlite(Tickets::Config::DB_PATH)
6
+
7
+ class Ticket < Sequel::Model(:tickets)
8
+ @@last_shook = Time.now
9
+
10
+ def self.needs_shaking?
11
+ (Time.now - @@last_shook) > Tickets::Config::SHAKE_INTERVAL*60*60
12
+ end
13
+
14
+ def self.shake!
15
+ Ticket.each do |ticket|
16
+ pos = ticket.emergency
17
+ dir = (ticket.importance < 0 ? 1 : -1)
18
+ newpos = pos + Tickets::Config::SHAKE_DISTANCE * dir
19
+ if newpos > (Tickets::Config::BOARD_WIDTH / 2)
20
+ newpos = (Tickets::Config::BOARD_WIDTH / 2)
21
+ end
22
+
23
+ ticket.update(:emergency => newpos) if newpos != pos
24
+ if newpos < -(Tickets::Config::BOARD_WIDTH / 2)
25
+ ticket.update(:deleted => true, :timeouted => true)
26
+ end
27
+ end
28
+ @@last_shook = Time.now
29
+ end
30
+ end
31
+
32
+ unless Ticket.table_exists?
33
+ migration_dir = File.expand_path("../db/migrate/",
34
+ File.dirname(__FILE__))
35
+ Sequel::Migrator.apply($db, migration_dir)
36
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007-2009 Yutaka Hara (http://route477.net)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,38 @@
1
+ ! BiwaScheme
2
+
3
+ BiwaScheme is a (yet another) Scheme interpreter written in JavaScript.
4
+
5
+ official page: http://mono.kmc.gr.jp/~yhara/w/?BiwaScheme
6
+
7
+ !! Files
8
+
9
+ !!! Core
10
+ :lib/biwascheme.js:for application(see hello_world.html)
11
+ :lib/stackbase.js:interpreter
12
+
13
+ !!! Libraries
14
+ :lib/r6rs_lib.js:library (R6RS functions)
15
+ :lib/webscheme_lib.js:library (functions which needs a browser)
16
+ :lib/extra_lib.js:library (other functions)
17
+ :lib/prototype.js:see http://prototypejs.org/
18
+
19
+ !!! Tests
20
+ :index.html:REPL (read-eval-print-loop)
21
+ :test/spec.html:Unit test of the interpreter (requires JSSpec)
22
+ :test/spidermonkey.sh:runner for SpiderMonkey (requires console_test.js)
23
+ :test/console_test.js:runner for CScript
24
+ :test/browser_test.js:runner for browsers (requires console_test.js)
25
+ :test/JSSpec.js:see http://jania.pe.kr/aw/moin.cgi/JSSpec
26
+ :test/JSSpec.css:used by JSSpec.js
27
+ :test/diff_match_patch.js:used by JSSpec.js
28
+
29
+ !! Acknowledgements
30
+
31
+ * Kent Dyvbig, Three implementation models for scheme
32
+ ** http://www.cs.indiana.edu/~dyb/pubs/3imp.pdf
33
+
34
+ !! Contact
35
+
36
+ yhara (HARA Yutaka)
37
+ yhara/at/kmc.gr.jp
38
+ http://mono.kmc.gr.jp/~yhara/
@@ -0,0 +1,101 @@
1
+ //for application
2
+
3
+ function dump(){}
4
+
5
+ var BiwaScheme = {
6
+ Version: 0.5,
7
+
8
+ // load library and execute proc after loading
9
+ require: function(src, check, proc){
10
+ var script = document.createElement('script')
11
+ script.src = src;
12
+ document.body.appendChild(script);
13
+
14
+ var checker = new Function("return !!(" + check + ")");
15
+
16
+ if(checker()) proc();
17
+ else setTimeout(function(){ checker() ? proc() : setTimeout(arguments.callee, 10); }, 10);
18
+ }
19
+ };
20
+
21
+ (function(){ //local namespace
22
+ var require = BiwaScheme.require;
23
+
24
+ // taken from prototype.js 1.6.0
25
+ var readAttribute = function(element, name) {
26
+ if (/*Prototype.Browser.IE*/ !!(window.attachEvent && !window.opera)){
27
+ var t = {
28
+ names: {
29
+ 'class': 'className',
30
+ 'for': 'htmlFor'
31
+ },
32
+ values: {
33
+ _getAttr: function(element, attribute) {
34
+ return element.getAttribute(attribute, 2);
35
+ },
36
+ _getAttrNode: function(element, attribute) {
37
+ var node = element.getAttributeNode(attribute);
38
+ return node ? node.value : "";
39
+ },
40
+ _getEv: function(element, attribute) {
41
+ var attribute = element.getAttribute(attribute);
42
+ return attribute ? attribute.toString().slice(23, -2) : null;
43
+ },
44
+ _flag: function(element, attribute) {
45
+ return $(element).hasAttribute(attribute) ? attribute : null;
46
+ },
47
+ style: function(element) {
48
+ return element.style.cssText.toLowerCase();
49
+ },
50
+ title: function(element) {
51
+ return element.title;
52
+ }
53
+ }
54
+ };
55
+ if (t.values[name]) return t.values[name](element, name);
56
+ if (t.names[name]) name = t.names[name];
57
+ if (name.indexOf(':') > -1){
58
+ return (!element.attributes || !element.attributes[name]) ? null :
59
+ element.attributes[name].value;
60
+ }
61
+ }
62
+ return element.getAttribute(name);
63
+ }
64
+
65
+ // main
66
+ var script = (function(e){
67
+ if(e.id == '_firebugConsole'){
68
+ return arguments.callee(document.body);
69
+ }
70
+ else if(e.nodeName.toLowerCase() == 'script'){
71
+ return e;
72
+ }
73
+ else{
74
+ return arguments.callee(e.lastChild);
75
+ }
76
+ })(document);
77
+
78
+ var src = readAttribute(script, 'src');
79
+ var dir = src.match(/(.*)biwascheme.js/)[1];
80
+
81
+ require(dir+'prototype.js', 'window.$$', function(){
82
+ require(dir+'stackbase.js', 'window.BiwaScheme.CoreEnv', function(){
83
+ require(dir+'r6rs_lib.js', 'window.BiwaScheme.CoreEnv["+"]', function(){
84
+ require(dir+'webscheme_lib.js', 'window.BiwaScheme.CoreEnv["getelem"]', function(){
85
+ require(dir+'extra_lib.js', 'window.BiwaScheme.CoreEnv["print"]', function(){
86
+ require(dir+'io.js', 'window.JSIO', function(){
87
+ var onError = function(e){
88
+ puts(e.message);
89
+ throw(e);
90
+ }
91
+ var biwascheme = new BiwaScheme.Interpreter(onError);
92
+ try{
93
+ biwascheme.evaluate(script.innerHTML, Prototype.emptyFunction);
94
+ }
95
+ catch(e){
96
+ onError(e);
97
+ }
98
+ })})})})})});
99
+ })();
100
+
101
+ //vim: set ft=javascript:
@@ -0,0 +1,513 @@
1
+
2
+ if( typeof(BiwaScheme)!='object' ) BiwaScheme={}; with(BiwaScheme) {
3
+ define_libfunc("html-escape", 1, 1, function(ar){
4
+ assert_string(ar[0]);
5
+ return ar[0].escapeHTML();
6
+ });
7
+ BiwaScheme.inspect_objs = function(objs){
8
+ return objs.map(function(obj){
9
+ if(obj.inspect)
10
+ return obj.inspect();
11
+ else
12
+ return Object.inspect($H(obj));
13
+ }).join(" ");
14
+ };
15
+ define_libfunc("inspect", 1, null, function(ar){
16
+ return BiwaScheme.inspect_objs(ar);
17
+ });
18
+ define_libfunc("inspect!", 1, null, function(ar){
19
+ return puts(BiwaScheme.inspect_objs(ar));
20
+ });
21
+
22
+ //
23
+ // json
24
+ //
25
+ // json->sexp
26
+ // Array -> list
27
+ // Object -> alist
28
+ // (number, boolean, string,
29
+ //
30
+ BiwaScheme.json2sexp = function(json){
31
+ switch(true){
32
+ case Object.isNumber(json) ||
33
+ Object.isString(json) ||
34
+ json === true || json === false:
35
+ return json;
36
+ case Object.isArray(json):
37
+ return json.map(function(item){
38
+ return json2sexp(item);
39
+ }).to_list();
40
+ case typeof(json) == "object":
41
+ var ls = nil;
42
+ for(key in json){
43
+ ls = new Pair(new Pair(key, json2sexp(json[key])),
44
+ ls);
45
+ }
46
+ return ls;
47
+ default:
48
+ throw new Error("json->sexp: detected invalid value for json: "+Object.inspect(json));
49
+ }
50
+ throw new Bug("must not happen");
51
+ }
52
+ define_libfunc("json->sexp", 1, 1, function(ar){
53
+ return json2sexp(ar[0]);
54
+ })
55
+
56
+ //
57
+ //from Gauche
58
+ //
59
+
60
+ define_libfunc("string-concat", 1, 1, function(ar){
61
+ assert_pair(ar[0]);
62
+ return ar[0].to_array().join("");
63
+ })
64
+ define_libfunc("string-split", 2, 2, function(ar){
65
+ assert_string(ar[0]);
66
+ assert_string(ar[1]);
67
+ return ar[0].split(ar[1]).to_list();
68
+ })
69
+ define_libfunc("string-join", 1, 2, function(ar){
70
+ assert_pair(ar[0]);
71
+ var delim = ""
72
+ if(ar[1]){
73
+ assert_string(ar[1]);
74
+ delim = ar[1];
75
+ }
76
+ return ar[0].to_array().join(delim);
77
+ })
78
+
79
+ define_libfunc("intersperse", 2, 2, function(ar){
80
+ var item = ar[0], ls = ar[1];
81
+ assert_pair(ls);
82
+
83
+ var ret = [];
84
+ ls.to_array().reverse().each(function(x){
85
+ ret.push(x);
86
+ ret.push(item);
87
+ });
88
+ ret.pop();
89
+ return ret.to_list();
90
+ });
91
+
92
+ //(define-macro (foo x) body ...)
93
+ //(define-macro foo lambda)
94
+
95
+ var rearrange_args = function (expected, given) {
96
+ var args = [];
97
+ var dotpos = (new Compiler).find_dot_pos(expected);
98
+ if (dotpos == -1)
99
+ args = given;
100
+ else {
101
+ for (var i = 0; i < dotpos; i++)
102
+ args[i] = given[i];
103
+ args[i] = given.slice(i).to_list();
104
+ }
105
+ return args;
106
+ }
107
+ define_syntax("define-macro", function(x){
108
+ var head = x.cdr.car;
109
+ var expected_args;
110
+ if(head instanceof Pair){
111
+ var name = head.car;
112
+ expected_args = head.cdr;
113
+ var body = x.cdr.cdr;
114
+ var lambda = new Pair(Sym("lambda"),
115
+ new Pair(expected_args,
116
+ body))
117
+ }
118
+ else{
119
+ var name = head;
120
+ var lambda = x.cdr.cdr.car;
121
+ expected_args = lambda.cdr.car;
122
+ }
123
+
124
+ //[close, n_frees, do_body, next]
125
+ var opc = Compiler.compile(lambda);
126
+ if(opc[1] != 0)
127
+ throw new Bug("you cannot use free variables in macro expander (or define-macro must be on toplevel)")
128
+ var cls = [opc[2]];
129
+
130
+ TopEnv[name.name] = new Syntax(function(sexp){
131
+ var given_args = sexp.to_array();
132
+
133
+ given_args.shift();
134
+
135
+ var intp = new Interpreter();
136
+ var args = rearrange_args(expected_args, given_args);
137
+ var result = intp.invoke_closure(cls, args);
138
+ return result;
139
+ })
140
+ })
141
+
142
+ var macroexpand_1 = function(x){
143
+ if(x instanceof Pair){
144
+ if(x.car instanceof Symbol && TopEnv[x.car.name] instanceof Syntax){
145
+ var transformer = TopEnv[x.car.name];
146
+ x = transformer.transform(x);
147
+ }
148
+ else
149
+ throw new Error("macroexpand-1: `" + to_write_ss(x) + "' is not a macro");
150
+ }
151
+ return x;
152
+ }
153
+ define_syntax("%macroexpand", function(x){
154
+ var expanded = (new Interpreter).expand(x.cdr.car);
155
+ return [Sym("quote"), expanded].to_list();
156
+ });
157
+ define_syntax("%macroexpand-1", function(x){
158
+ var expanded = macroexpand_1(x.cdr.car);
159
+ return [Sym("quote"), expanded].to_list();
160
+ });
161
+
162
+ define_libfunc("macroexpand", 1, 1, function(ar){
163
+ return (new Interpreter).expand(ar[0]);
164
+ });
165
+ define_libfunc("macroexpand-1", 1, 1, function(ar){
166
+ return macroexpand_1(ar[0]);
167
+ });
168
+
169
+ define_libfunc("print", 1, null, function(ar){
170
+ ar.map(function(item){
171
+ puts(to_display(item), true);
172
+ })
173
+ puts(""); //newline
174
+ })
175
+ define_syntax("let1", function(x){
176
+ //(let1 vari expr body ...)
177
+ //=> ((lambda (var) body ...) expr)
178
+ var vari = x.cdr.car;
179
+ var expr = x.cdr.cdr.car;
180
+ var body = x.cdr.cdr.cdr;
181
+
182
+ return new Pair(new Pair(Sym("lambda"),
183
+ new Pair(new Pair(vari, nil),
184
+ body)),
185
+ new Pair(expr, nil));
186
+ })
187
+
188
+ define_libfunc("write-to-string", 1, 1, function(ar){
189
+ return to_write(ar[0]);
190
+ });
191
+ define_libfunc("read-from-string", 1, 1, function(ar){
192
+ assert_string(ar[0]);
193
+ return new Parser(ar[0]).getObject();
194
+ });
195
+
196
+ //
197
+ // srfi
198
+ //
199
+
200
+ // srfi-1 (list)
201
+ define_libfunc("iota", 1, 3, function(ar){
202
+ var count = ar[0];
203
+ var start = ar[1] || 0;
204
+ var step = (ar[2]===undefined) ? 1 : ar[2];
205
+ assert_integer(count);
206
+ assert_number(start);
207
+ assert_number(step);
208
+
209
+ var a = [], n = start;
210
+ for(var i=0; i<count; i++){
211
+ a.push(n);
212
+ n += step;
213
+ }
214
+ return a.to_list();
215
+ });
216
+
217
+ // srfi-6 & Gauche (string port)
218
+ BiwaScheme.Port.StringOutput = Class.create(Port, {
219
+ initialize: function($super){
220
+ this.buffer = [];
221
+ $super(false, true);
222
+ },
223
+ put_string: function(str){
224
+ this.buffer.push(str);
225
+ },
226
+ output_string: function(str){
227
+ return this.buffer.join("");
228
+ }
229
+ });
230
+ BiwaScheme.Port.StringInput = Class.create(Port, {
231
+ initialize: function($super){
232
+ $super(true, false);
233
+ },
234
+ get_string: function(after){
235
+ }
236
+ });
237
+ define_libfunc("open-input-string", 1, 1, function(ar){
238
+ assert_string(ar[0]);
239
+ return new Port.StringInput(ar[0]);
240
+ })
241
+ define_libfunc("open-output-string", 0, 0, function(ar){
242
+ return new Port.StringOutput();
243
+ })
244
+ define_libfunc("get-output-string", 1, 1, function(ar){
245
+ assert_port(ar[0]);
246
+ if(!(ar[0] instanceof Port.StringOutput))
247
+ throw new Error("get-output-string: port must be made by 'open-output-string'");
248
+ return ar[0].output_string();
249
+ })
250
+
251
+ // srfi-19 (time)
252
+ //
253
+ // // constants
254
+ //time-duration
255
+ //time-monotonic
256
+ //time-process
257
+ //time-tai
258
+ //time-thread
259
+ //time-utc
260
+ // Current time and clock resolution
261
+ define_libfunc("current-date", 0, 1, function(ar){
262
+ //todo: tz-offset (ar[1])
263
+ return new Date();
264
+ })
265
+ //
266
+ //current-julian-day -> jdn
267
+ //current-modified-julian-day -> mjdn
268
+ //current-time [time-type] -> time
269
+ //time-resolution [time-type] -> integer
270
+ // // Time object and accessors
271
+ //make-time type nanosecond second -> time
272
+ //time? object -> boolean
273
+ //time-type time -> time-type
274
+ //time-nanosecond time -> integer
275
+ //time-second time -> integer
276
+ //set-time-type! time time-type
277
+ //set-time-nanosecond! time integer
278
+ //set-time-second! time integer
279
+ //copy-time time1 -> time2
280
+ // // Time comparison procedures
281
+ //time<=? time1 time2 -> boolean
282
+ //time<? time1 time2 -> boolean
283
+ //time=? time1 time2 -> boolean
284
+ //time>=? time1 time2 -> boolean
285
+ //time>? time1 time2 -> boolean
286
+ // // Time arithmetic procedures
287
+ //time-difference time1 time2 -> time-duration
288
+ //time-difference! time1 time2 -> time-duration
289
+ //add-duration time1 time-duration -> time
290
+ //add-duration! time1 time-duration -> time
291
+ //subtract-duration time1 time-duration -> time
292
+ //subtract-duration! time1 time-duration -> time
293
+ // Date object and accessors
294
+ // make-date
295
+ define_libfunc("date?", 1, 1, function(ar){
296
+ return (ar[0] instanceof Date);
297
+ })
298
+ define_libfunc("date-nanosecond", 1, 1, function(ar){
299
+ assert_date(ar[0]);
300
+ return ar[0].getMilliseconds() * 1000000;
301
+ })
302
+ define_libfunc("date-millisecond", 1, 1, function(ar){ // not srfi-19
303
+ assert_date(ar[0]);
304
+ return ar[0].getMilliseconds();
305
+ })
306
+ define_libfunc("date-second", 1, 1, function(ar){
307
+ assert_date(ar[0]);
308
+ return ar[0].getSeconds();
309
+ })
310
+ define_libfunc("date-minute", 1, 1, function(ar){
311
+ assert_date(ar[0]);
312
+ return ar[0].getMinutes();
313
+ })
314
+ define_libfunc("date-hour", 1, 1, function(ar){
315
+ assert_date(ar[0]);
316
+ return ar[0].getHours();
317
+ })
318
+ define_libfunc("date-day", 1, 1, function(ar){
319
+ assert_date(ar[0]);
320
+ return ar[0].getDate();
321
+ })
322
+ define_libfunc("date-month", 1, 1, function(ar){
323
+ assert_date(ar[0]);
324
+ return ar[0].getMonth() + 1; //Jan = 0 in javascript..
325
+ })
326
+ define_libfunc("date-year", 1, 1, function(ar){
327
+ assert_date(ar[0]);
328
+ return ar[0].getFullYear();
329
+ })
330
+ //date-zone-offset
331
+ //date-year-day
332
+ define_libfunc("date-week-day", 1, 1, function(ar){
333
+ assert_date(ar[0]);
334
+ return ar[0].getDay();
335
+ })
336
+ //date-week-number
337
+
338
+ // Time/Date/Julian Day/Modified Julian Day Converters
339
+ // (snipped)
340
+
341
+ // Date to String/String to Date Converters
342
+ // TODO: support locale
343
+ // * date_names
344
+ // * ~f 5.2 sec
345
+ // * ~p AM/PM
346
+ // * ~X 2007/01/01
347
+ BiwaScheme.date_names = {
348
+ weekday: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
349
+ full_weekday: ["Sunday", "Monday", "Tuesday",
350
+ "Wednesday", "Thursday", "Friday", "Saturday"],
351
+ month: ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
352
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
353
+ full_month: ["January", "February", "March", "April",
354
+ "May", "June", "July", "August", "September",
355
+ "Octorber", "November", "December"]
356
+ }
357
+
358
+ BiwaScheme.date2string = function(date, format){
359
+ var zeropad = function(n){ return n<10 ? "0"+n : ""+n };
360
+ var spacepad = function(n){ return n<10 ? " "+n : ""+n };
361
+
362
+ var getter = {
363
+ a: function(x){ return date_names.weekday[x.getDay()] },
364
+ A: function(x){ return date_names.full_weekday[x.getDay()] },
365
+ b: function(x){ return date_names.month[x.getMonth()] },
366
+ B: function(x){ return date_names.full_month[x.getMonth()] },
367
+ c: function(x){ return x.toString() },
368
+ d: function(x){ return zeropad(x.getDate()) },
369
+ D: function(x){ return getter.d(x) + getter.m(x) + getter.y(x); },
370
+ e: function(x){ return spacepad(x.getDate()) },
371
+ f: function(x){ return x.getSeconds() + x.getMilliseconds()/1000; },
372
+ h: function(x){ return date_names.month[x.getMonth()] },
373
+ H: function(x){ return zeropad(x.getHours()) },
374
+ I: function(x){ var h = x.getHours(); return zeropad(h<13 ? h : h-12) },
375
+ j: function(x){ throw new Bug("not implemented: day of year") },
376
+ k: function(x){ return spacepad(x.getHours()) },
377
+ l: function(x){ var h = x.getHours(); return spacepad(h<13 ? h : h-12) },
378
+ m: function(x){ return zeropad(x.getMonth()) },
379
+ M: function(x){ return zeropad(x.getMinutes()) },
380
+ n: function(x){ return "\n" },
381
+ N: function(x){ throw new Bug("not implemented: nanoseconds") },
382
+ p: function(x){ return x.getHours()<13 ? "AM" : "PM" },
383
+ r: function(x){ return getter.I(x) + ":" + getter.M(x) + ":" + getter.S(x) + " " + getter.p(x) },
384
+ s: function(x){ return Math.floor(x.getTime() / 1000) },
385
+ S: function(x){ return zeropad(x.getSeconds()) },
386
+ t: function(x){ return "\t" },
387
+ T: function(x){ return getter.H(x) + ":" + getter.M(x) + ":" + getter.S(x) },
388
+ U: function(x){ throw new Bug("not implemented: weeknum(0~, Sun)") },
389
+ V: function(x){ throw new Bug("not implemented: weeknum(1~, Sun?)") },
390
+ w: function(x){ return x.getDay() },
391
+ W: function(x){ throw new Bug("not implemented: weeknum(0~, Mon)") },
392
+ x: function(x){ throw new Bug("not implemented: weeknum(1~, Mon)") },
393
+ X: function(x){ return getter.Y(x) + "/" + getter.m(x) + "/" + getter.d(x) },
394
+ y: function(x){ return x.getFullYear() % 100 },
395
+ Y: function(x){ return x.getFullYear() },
396
+ z: function(x){ throw new Bug("not implemented: time-zone") },
397
+ Z: function(x){ throw new Bug("not implemented: symbol time zone") },
398
+ 1: function(x){ throw new Bug("not implemented: ISO-8601 year-month-day format") },
399
+ 2: function(x){ throw new Bug("not implemented: ISO-8601 hour-minute-second-timezone format") },
400
+ 3: function(x){ throw new Bug("not implemented: ISO-8601 hour-minute-second format") },
401
+ 4: function(x){ throw new Bug("not implemented: ISO-8601 year-month-day-hour-minute-second-timezone format") },
402
+ 5: function(x){ throw new Bug("not implemented: ISO-8601 year-month-day-hour-minute-second format") }
403
+ }
404
+
405
+ return format.replace(/~([\w1-5~])/g, function(_, x){
406
+ var func = getter[x];
407
+ if(func)
408
+ return func(date);
409
+ else if(x == "~")
410
+ return "~";
411
+ else
412
+ return x;
413
+ })
414
+ }
415
+
416
+ // date->string
417
+ define_libfunc("date->string", 1, 2, function(ar){
418
+ assert_date(ar[0]);
419
+
420
+ if(ar[1]){
421
+ assert_string(ar[1]);
422
+ return date2string(ar[0], ar[1]);
423
+ }
424
+ else
425
+ return ar[0].toString();
426
+ })
427
+ // string->date
428
+
429
+ define_libfunc("parse-date", 1, 1, function(ar){ // not srfi-19
430
+ assert_string(ar[0]);
431
+ return new Date(Date.parse(ar[0]));
432
+ })
433
+
434
+ //
435
+ // srfi-38 (write/ss)
436
+ //
437
+ var user_write_ss = function(ar){
438
+ puts(write_ss(ar[0]), true);
439
+ }
440
+ define_libfunc("write/ss", 1, 2, user_write_ss);
441
+ define_libfunc("write-with-shared-structure", 1, 2, user_write_ss);
442
+ define_libfunc("write*", 1, 2, user_write_ss); //from Gauche(STklos)
443
+
444
+ //
445
+ // srfi-43 (vector library)
446
+ //
447
+ define_libfunc("vector-append", 2, null, function(ar){
448
+ var vec = [];
449
+ return vec.concat.apply(vec, ar);
450
+ })
451
+
452
+ //
453
+ // Regular Expression
454
+ //
455
+ var assert_regexp = function(obj, fname){
456
+ if(!(obj instanceof RegExp))
457
+ throw new Error(fname + ": regexp required, but got " + to_write(obj));
458
+ }
459
+
460
+ //Function: string->regexp string &keyword case-fold
461
+ define_libfunc("string->regexp", 1, 1, function(ar){
462
+ assert_string(ar[0], "string->regexp");
463
+ return new RegExp(ar[0]); //todo: case-fold
464
+ })
465
+ //Function: regexp? obj
466
+ define_libfunc("regexp?", 1, 1, function(ar){
467
+ return (ar[0] instanceof RegExp);
468
+ })
469
+ //Function: regexp->string regexp
470
+ define_libfunc("regexp->string", 1, 1, function(ar){
471
+ assert_regexp(ar[0], "regexp->string");
472
+ return ar[0].toString().slice(1, -1); //cut '/'
473
+ })
474
+
475
+ define_libfunc("regexp-exec", 2, 2, function(ar){
476
+ var rexp = ar[0];
477
+ if(Object.isString(ar[0])){
478
+ rexp = new RegExp(ar[0]);
479
+ }
480
+ assert_regexp(rexp, "regexp-exec");
481
+ assert_string(ar[1], "regexp-exec");
482
+ var ret = rexp.exec(ar[1])
483
+ return (ret === null) ? false : ret.to_list();
484
+ })
485
+
486
+ // //Function: rxmatch regexp string
487
+ // define_libfunc("rxmatch", 1, 1, function(ar){
488
+ // assert_regexp(ar[0], "rxmatch");
489
+ // assert_string(ar[1], "rxmatch");
490
+ // return ar[0].match(ar[1]);
491
+ // });
492
+ //Function: rxmatch-start match &optional (i 0)
493
+ //Function: rxmatch-end match &optional (i 0)
494
+ //Function: rxmatch-substring match &optional (i 0)
495
+ //Function: rxmatch-num-matches match
496
+ //Function: rxmatch-after match &optional (i 0)
497
+ //Function: rxmatch-before match &optional (i 0)
498
+ //Generic application: regmatch &optional index
499
+ //Generic application: regmatch 'before &optional index
500
+ //Generic application: regmatch 'after &optional index
501
+ //Function: regexp-replace regexp string substitution
502
+ //Function: regexp-replace-all regexp string substitution
503
+ //Function: regexp-replace* string rx1 sub1 rx2 sub2 ...
504
+ //Function: regexp-replace-all* string rx1 sub1 rx2 sub2 ...
505
+ //Function: regexp-quote string
506
+ //Macro: rxmatch-let match-expr (var ...) form ...
507
+ //Macro: rxmatch-if match-expr (var ...) then-form else-form
508
+ //Macro: rxmatch-cond clause ...
509
+ //Macro: rxmatch-case string-expr clause ...
510
+
511
+ }
512
+
513
+