yhara-tickets 0.1.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.
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
+