diametric 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,147 +1,777 @@
1
1
  package diametric;
2
2
 
3
- import java.util.Collection;
4
3
  import java.util.Iterator;
4
+ import java.util.List;
5
5
 
6
6
  import org.jruby.Ruby;
7
+ import org.jruby.RubyArray;
8
+ import org.jruby.RubyBoolean;
7
9
  import org.jruby.RubyClass;
10
+ import org.jruby.RubyFixnum;
8
11
  import org.jruby.RubyObject;
12
+ import org.jruby.RubyRange;
13
+ import org.jruby.RubyString;
9
14
  import org.jruby.anno.JRubyClass;
10
15
  import org.jruby.anno.JRubyMethod;
11
16
  import org.jruby.javasupport.JavaUtil;
17
+ import org.jruby.runtime.Arity;
12
18
  import org.jruby.runtime.Block;
13
19
  import org.jruby.runtime.ThreadContext;
14
20
  import org.jruby.runtime.builtin.IRubyObject;
15
21
 
22
+ import clojure.lang.APersistentVector;
23
+ import clojure.lang.LazySeq;
24
+ import clojure.lang.PersistentVector;
25
+ import clojure.lang.Var;
26
+
16
27
  @JRubyClass(name = "Diametric::Persistence::Collection")
17
28
  public class DiametricCollection extends RubyObject {
18
29
  // should be a Ruby's Enumerable
19
30
  private static final long serialVersionUID = 7656855654760249694L;
20
- private Collection query_result = null;
31
+ private List vector_or_seq = null;
32
+ private Integer count = null; // unable to count the vector size that exceeds Integer
33
+ private DiametricCommon common = null;
21
34
 
22
35
  public DiametricCollection(Ruby runtime, RubyClass klazz) {
23
36
  super(runtime, klazz);
24
37
  }
25
-
26
- void init(Object result) {
27
- if (result instanceof Collection) {
28
- this.query_result = (Collection)result;
38
+
39
+ void init(Object obj) {
40
+ if ((obj instanceof APersistentVector) ||
41
+ (obj instanceof LazySeq) ||
42
+ (obj instanceof PersistentVector.ChunkedSeq)) {
43
+ this.vector_or_seq = (List)obj;
29
44
  } else {
30
45
  throw new RuntimeException("Wrong type of query result");
31
46
  }
47
+ common = new DiametricCommon();
32
48
  }
33
49
 
34
50
  Object toJava() {
35
- return query_result;
51
+ return vector_or_seq;
52
+ }
53
+
54
+ @JRubyMethod(meta=true)
55
+ public static IRubyObject wrap(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
56
+ try {
57
+ clojure.lang.PersistentVector value =
58
+ (clojure.lang.PersistentVector)arg.toJava(clojure.lang.PersistentVector.class);
59
+ return DiametricUtils.getDiametricCollection(context, (List)value);
60
+ } catch (Throwable t) {
61
+ throw context.getRuntime().newRuntimeError(t.getMessage());
62
+ }
63
+ }
64
+
65
+ @JRubyMethod(meta=true)
66
+ public static IRubyObject be_lazy(ThreadContext context, IRubyObject klazz, IRubyObject arg) {
67
+ try {
68
+ clojure.lang.PersistentVector v =
69
+ (clojure.lang.PersistentVector)arg.toJava(clojure.lang.PersistentVector.class);
70
+ Var var = DiametricService.getFn("clojure.core", "take");
71
+ Object value = var.invoke(100, v);
72
+ return DiametricUtils.getDiametricCollection(context, (List)value);
73
+ } catch (Throwable t) {
74
+ throw context.getRuntime().newRuntimeError(t.getMessage());
75
+ }
36
76
  }
37
77
 
38
78
  @JRubyMethod
39
79
  public IRubyObject to_java(ThreadContext context) {
40
- return JavaUtil.convertJavaToUsableRubyObject(context.getRuntime(), query_result);
80
+ return JavaUtil.convertJavaToUsableRubyObject(context.getRuntime(), vector_or_seq);
41
81
  }
42
-
43
- @JRubyMethod(name="==", required=1)
44
- public IRubyObject op_equal(ThreadContext context, IRubyObject arg) {
45
- Ruby runtime = context.getRuntime();
46
- if (arg instanceof DiametricCollection) {
47
- DiametricCollection other = (DiametricCollection)arg;
48
- if (query_result.toString().equals(other.toJava().toString())) {
49
- return runtime.getTrue();
82
+
83
+ @JRubyMethod(name="&")
84
+ public IRubyObject op_and(ThreadContext context, IRubyObject arg) {
85
+ throw context.getRuntime().newRuntimeError("Not supported. Perhaps, doesn't make sense for query result.");
86
+ }
87
+
88
+ @JRubyMethod(name="-")
89
+ public IRubyObject op_diff(ThreadContext context, IRubyObject arg) {
90
+ if (!(arg instanceof List)) {
91
+ throw context.getRuntime().newRuntimeError("argument should be array");
92
+ }
93
+ List other = (List)arg;
94
+ Var two_arrays_diff_fn = null;
95
+ if (DiametricService.fnMap.containsKey("two-arrays-diff")) {
96
+ two_arrays_diff_fn = DiametricService.fnMap.get("two-arrays-diff");
97
+ } else {
98
+ Var var = DiametricService.getFn("clojure.core", "load-string");
99
+ String fn =
100
+ "(defn two-arrays-diff [this other]\n" +
101
+ " (let [f (fn [ary n] (remove (partial = n) ary))]\n"+
102
+ " (reduce f this other)))";
103
+ two_arrays_diff_fn = (Var)var.invoke(fn);
104
+ DiametricService.fnMap.put("two-arrays-diff", two_arrays_diff_fn);
105
+ }
106
+ try {
107
+ Object value = two_arrays_diff_fn.invoke(vector_or_seq, other);
108
+ return DiametricUtils.getDiametricCollection(context, (List)value);
109
+ } catch (Throwable t) {
110
+ throw context.getRuntime().newRuntimeError(t.getMessage());
111
+ }
112
+ }
113
+
114
+ @JRubyMethod(name="*")
115
+ public IRubyObject op_times(ThreadContext context, IRubyObject arg) {
116
+ if (arg instanceof RubyFixnum) {
117
+ Var append_n_times_fn = null;
118
+ if (DiametricService.fnMap.containsKey("append-n-times")) {
119
+ append_n_times_fn = DiametricService.fnMap.get("append-n-times");
120
+ } else {
121
+ Var var = DiametricService.getFn("clojure.core", "load-string");
122
+ append_n_times_fn = (Var)var.invoke("(defn append-n-times [n array] (reduce concat (replicate n array)))");
123
+ DiametricService.fnMap.put("append-n-times", append_n_times_fn);
124
+ }
125
+ Integer n = (Integer)arg.toJava(Integer.class);
126
+ try {
127
+ Object value = append_n_times_fn.invoke(n, vector_or_seq);
128
+ return DiametricUtils.getDiametricCollection(context, (List)value);
129
+ } catch (Throwable t) {
130
+ throw context.getRuntime().newRuntimeError(t.getMessage());
131
+ }
132
+ } else if (arg instanceof RubyString) {
133
+ return join(context, arg);
134
+ } else {
135
+ throw context.getRuntime().newArgumentError("argument should be either String or Fixnum");
136
+ }
137
+ }
138
+
139
+ @JRubyMethod(name="+")
140
+ public IRubyObject op_plus(ThreadContext context, IRubyObject arg) {
141
+ if (!(arg instanceof List)) {
142
+ throw context.getRuntime().newRuntimeError("argument should be array");
143
+ }
144
+ List other = (List)arg;
145
+ try {
146
+ Var var = DiametricService.getFn("clojure.core", "concat");
147
+ Object value = var.invoke(vector_or_seq, other);
148
+ return DiametricUtils.getDiametricCollection(context, (List)value);
149
+ } catch (Throwable t) {
150
+ throw context.getRuntime().newRuntimeError(t.getMessage());
151
+ }
152
+ }
153
+
154
+ @JRubyMethod(name="<<")
155
+ public IRubyObject op_append(ThreadContext context) {
156
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
157
+ }
158
+
159
+ @JRubyMethod(name="<=>")
160
+ public IRubyObject op_cmp(ThreadContext context, IRubyObject arg) {
161
+ if (!(arg instanceof List)) return context.getRuntime().getNil();
162
+ List other = (List)arg;
163
+ try {
164
+ Var var = DiametricService.getFn("clojure.core", "compare");
165
+ Integer value = (Integer)var.invoke(vector_or_seq, other);
166
+ return context.getRuntime().newFixnum(value);
167
+ } catch (Throwable t) {
168
+ throw context.getRuntime().newRuntimeError(t.getMessage());
169
+ }
170
+ }
171
+
172
+ @JRubyMethod(name={"[]", "slice"}, required=1, optional=1)
173
+ public IRubyObject aref(ThreadContext context, IRubyObject[] args) {
174
+ /*
175
+ * ary[index] -> obj or nil
176
+ * ary[start, length] -> new_ary or nil
177
+ * ary[range] -> new_ary or nil
178
+ * slice(index) -> obj or nil
179
+ * slice(start,length) -> new_ary or_nil
180
+ * slice(range) -> new_ary or nil
181
+ */
182
+ switch(args.length) {
183
+ case 1:
184
+ return aref(context, args[0]);
185
+ case 2:
186
+ return aref(context, args[0], args[1]);
187
+ default:
188
+ Arity.raiseArgumentError(getRuntime(), args.length, 1, 2);
189
+ }
190
+ return context.getRuntime().getNil();
191
+ }
192
+
193
+ private IRubyObject aref(ThreadContext context, IRubyObject index_or_range) {
194
+ if (index_or_range instanceof RubyFixnum) {
195
+ Long index = (Long)index_or_range.toJava(Long.class);
196
+ return commonArefIndex(context, index);
197
+ } else if (index_or_range instanceof RubyRange) {
198
+ RubyRange range = (RubyRange)index_or_range;
199
+ Long start = (Long)range.first().toJava(Long.class);
200
+ Long last = (Long)range.last().toJava(Long.class);
201
+ // subvec returns from 'start' to element (- end 1)
202
+ if (range.exclude_end_p().isTrue()) {
203
+ return commonAref(context, start, null, last);
204
+ } else {
205
+ return commonAref(context, start, null, last + 1);
206
+ }
207
+ } else {
208
+ throw context.getRuntime().newArgumentError("wrong argument");
209
+ }
210
+ }
211
+
212
+ private IRubyObject aref(ThreadContext context, IRubyObject arg0, IRubyObject arg1) {
213
+ Long start = (Long)arg0.toJava(Long.class);
214
+ Long length = (Long)arg1.toJava(Long.class);
215
+ if (length < 0L) return context.getRuntime().getNil();
216
+ try {
217
+ return commonAref(context, start, length, null);
218
+ } catch (Throwable t) {
219
+ throw context.getRuntime().newRuntimeError(t.getMessage());
220
+ }
221
+ }
222
+
223
+ private IRubyObject commonArefIndex(ThreadContext context, Long index) {
224
+ try {
225
+ Var var = DiametricService.getFn("clojure.core", "nth");
226
+ Object value = var.invoke(vector_or_seq, index);
227
+ return DiametricUtils.convertJavaToRuby(context, value);
228
+ } catch (Throwable t) {
229
+ if (t instanceof IndexOutOfBoundsException) {
230
+ // raised only from [index] when index is greater than the last index or negative
231
+ if (index >= (long)getCount()) return context.getRuntime().getNil();
232
+ if (index < 0L) index += (long)getCount();
233
+ if (index < 0L) return context.getRuntime().getNil();
234
+ return commonArefIndex(context, index);
235
+ }
236
+ throw context.getRuntime().newRuntimeError(t.getMessage());
237
+ }
238
+ }
239
+
240
+ private IRubyObject commonAref(ThreadContext context, Long start, Long length, Long last) {
241
+ try {
242
+ Object value = null;
243
+ if (vector_or_seq instanceof APersistentVector) {
244
+ long end = length != null ? (start + length) : last;
245
+ // checking a vector's length may be a costly operation.
246
+ // allows to raise exception for the first time
247
+ value = commonArefBySubvec(start, end);
248
+ } else {
249
+ // negative drop doesn't raise exception
250
+ // too big number for take doesn't raise exception
251
+ if (start > (long)getCount()) return context.getRuntime().getNil();
252
+ if (start == (long)getCount()) return context.getRuntime().newEmptyArray();
253
+ if (start < 0L) start += (long)getCount();
254
+ if (start < 0L) return context.getRuntime().getNil();
255
+ if (length == null) length = last - start;
256
+ value = commonArefByDropTake(start, length);
257
+ }
258
+ return DiametricUtils.getDiametricCollection(context, (List)value);
259
+ } catch (Throwable t) {
260
+ if (t instanceof IndexOutOfBoundsException) {
261
+ return retryAref(context, start, length, last);
262
+ }
263
+ throw context.getRuntime().newRuntimeError(t.getMessage());
264
+ }
265
+ }
266
+
267
+ private Object commonArefBySubvec(Long start, Long end) {
268
+ Var var = DiametricService.getFn("clojure.core", "subvec");
269
+ // subvec returns from 'start' to element (- end 1)
270
+ return var.invoke(vector_or_seq, start, end);
271
+ }
272
+
273
+ private Object commonArefByDropTake(Long start, Long length) {
274
+ Var seq_subvec_fn = null;
275
+ if (DiametricService.fnMap.containsKey("seq-subvec")) {
276
+ seq_subvec_fn = DiametricService.fnMap.get("seq-subvec");
277
+ } else {
278
+ Var var = DiametricService.getFn("clojure.core", "load-string");
279
+ seq_subvec_fn = (Var)var.invoke("(defn seq-subvec [seq start length] (take length (drop start seq)))");
280
+ DiametricService.fnMap.put("seq-subvec", seq_subvec_fn);
281
+ }
282
+ return seq_subvec_fn.invoke(vector_or_seq, start, length);
283
+ }
284
+
285
+ private IRubyObject retryAref(ThreadContext context, Long start, Long length, Long last) {
286
+ // now, check the vector's length
287
+ if (start > (long)getCount()) return context.getRuntime().getNil();
288
+ if (start == (long)getCount()) return context.getRuntime().newEmptyArray();
289
+ if (start < 0L) start += (long)getCount();
290
+ if (start < 0L) return context.getRuntime().getNil();
291
+
292
+ long end = length != null ? (start + length) : last;
293
+ end = (end <= (long)getCount()) ? end : (long)getCount();
294
+ return commonAref(context, start, null, end);
295
+ }
296
+
297
+ @JRubyMethod
298
+ public IRubyObject assoc(ThreadContext context, IRubyObject arg) {
299
+ throw context.getRuntime().newRuntimeError("Not yet supported. Might be implented later depends on datomic queries.");
300
+ }
301
+
302
+ @JRubyMethod
303
+ public IRubyObject at(ThreadContext context, IRubyObject arg) {
304
+ Long index = null;
305
+ try {
306
+ if (arg instanceof RubyFixnum) {
307
+ index = (Long)arg.toJava(Long.class);
308
+ return commonArefIndex(context, index);
50
309
  } else {
51
- return runtime.getFalse();
310
+ throw context.getRuntime().newArgumentError("argument should be fixnum");
52
311
  }
312
+ } catch (Throwable t) {
313
+ if (t instanceof IndexOutOfBoundsException) {
314
+ // raised only when index is greater than the last index or negative
315
+ if (index >= (long)getCount()) return context.getRuntime().getNil();
316
+ if (index < 0L) index += (long)getCount();
317
+ if (index < 0L) return context.getRuntime().getNil();
318
+ return commonArefIndex(context, index);
319
+ }
320
+ throw context.getRuntime().newRuntimeError(t.getMessage());
321
+ }
322
+ }
323
+
324
+ @JRubyMethod
325
+ public IRubyObject bsearch(ThreadContext context, Block block) {
326
+ throw context.getRuntime().newRuntimeError("bsearch is not supported.");
327
+ }
328
+
329
+ @JRubyMethod
330
+ public IRubyObject clear(ThreadContext context) {
331
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
332
+ }
333
+
334
+ @JRubyMethod(name={"collect", "map"})
335
+ public IRubyObject collect(ThreadContext context, Block block) {
336
+ if (block.isGiven()) {
337
+ return common.collect(context, block, vector_or_seq.iterator());
53
338
  } else {
54
- return runtime.getFalse();
339
+ return this;
55
340
  }
56
341
  }
57
342
 
343
+ @JRubyMethod(name={"collect!", "map!"})
344
+ public IRubyObject collect_bang(ThreadContext context, Block block) {
345
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
346
+ }
347
+
58
348
  @JRubyMethod
59
- public IRubyObject to_s(ThreadContext context) {
60
- return context.getRuntime().newString(query_result.toString());
349
+ public IRubyObject combination(ThreadContext context, IRubyObject arg, Block block) {
350
+ throw context.getRuntime().newRuntimeError("Not supported yet. Perhaps, doesn't make sense for query result.");
351
+ }
352
+
353
+ @JRubyMethod
354
+ public IRubyObject compact(ThreadContext context) {
355
+ try {
356
+ Var var = DiametricService.getFn("clojure.core", "remove");
357
+ Var nil_p = DiametricService.getFn("clojure.core", "nil?");
358
+ LazySeq value = (LazySeq) var.invoke(nil_p, vector_or_seq);
359
+ Iterator itr = value.iterator();
360
+ RubyArray result = context.getRuntime().newArray();
361
+ while (itr.hasNext()) {
362
+ Object obj = itr.next();
363
+ result.callMethod("<<", DiametricUtils.convertJavaToRuby(context, obj));
364
+ }
365
+ return result;
366
+ } catch (Throwable t) {
367
+ throw context.getRuntime().newRuntimeError(t.getMessage());
368
+ }
369
+ }
370
+
371
+ @JRubyMethod(name="compact!")
372
+ public IRubyObject compact_bang(ThreadContext context) {
373
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
374
+ }
375
+
376
+ @JRubyMethod
377
+ public IRubyObject concat(ThreadContext context, IRubyObject arg) {
378
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
379
+ }
380
+
381
+ @JRubyMethod
382
+ public IRubyObject count(ThreadContext context, Block block) {
383
+ if (block.isGiven()) {
384
+ return common.count(context, block, vector_or_seq.iterator());
385
+ } else {
386
+ return context.getRuntime().newFixnum(getCount());
387
+ }
388
+ }
389
+
390
+ @JRubyMethod(required = 1)
391
+ public IRubyObject count(ThreadContext context, IRubyObject arg, Block block) {
392
+ if (block.isGiven()) {
393
+ throw context.getRuntime().newArgumentError("given block not used");
394
+ } else {
395
+ return common.count(context, arg, vector_or_seq);
396
+ }
397
+ }
398
+
399
+ @JRubyMethod
400
+ public IRubyObject cycle(ThreadContext context, Block block) {
401
+ throw context.getRuntime().newRuntimeError("Not supported yet. Perhaps, doesn't make sense for query result.");
402
+ }
403
+
404
+ @JRubyMethod
405
+ public IRubyObject cycle(ThreadContext context, IRubyObject arg, Block block) {
406
+ throw context.getRuntime().newRuntimeError("Not supported yet. Perhaps, doesn't make sense for query result.");
407
+ }
408
+
409
+ @JRubyMethod
410
+ public IRubyObject delete(ThreadContext context, IRubyObject arg, Block block) {
411
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
412
+ }
413
+
414
+ @JRubyMethod(name={"delete_at", "slice!"}, required=1, optional=1)
415
+ public IRubyObject delete_at(ThreadContext context, IRubyObject arg[]) {
416
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
417
+ }
418
+
419
+ @JRubyMethod(name={"delete_if", "reject!"})
420
+ public IRubyObject delete_if(ThreadContext context, Block block) {
421
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
422
+ }
423
+
424
+ @JRubyMethod(name={"drop", "take"})
425
+ public IRubyObject drop(ThreadContext context, IRubyObject arg) {
426
+ if (!(arg instanceof RubyFixnum)) {
427
+ throw context.getRuntime().newArgumentError("argument should be Fixnum");
428
+ }
429
+ Long n = (Long)arg.toJava(Long.class);
430
+ if (n < 0) {
431
+ throw context.getRuntime().newArgumentError("negative drop size");
432
+ }
433
+ if (n == 0) return this;
434
+ return common.drop_or_take(context, n, vector_or_seq);
435
+ }
436
+
437
+ @JRubyMethod(name={"drop_while", "take_while"})
438
+ public IRubyObject drop_while(ThreadContext context, Block block) {
439
+ if (block.isGiven()) {
440
+ return common.drop_while(context, block, vector_or_seq.iterator());
441
+ } else {
442
+ return this;
443
+ }
444
+ }
445
+
446
+ @JRubyMethod
447
+ public IRubyObject each(ThreadContext context, Block block) {
448
+ if (block.isGiven()) {
449
+ common.each(context, block, vector_or_seq.iterator());
450
+ }
451
+ return this;
452
+ }
453
+
454
+ @JRubyMethod
455
+ public IRubyObject each_index(ThreadContext context, Block block) {
456
+ if (block.isGiven()) {
457
+ Iterator<Object> itr = vector_or_seq.iterator();
458
+ Long index = 0L;
459
+ while (itr.hasNext()) {
460
+ itr.next();
461
+ block.yield(context, context.getRuntime().newFixnum(index));
462
+ index++;
463
+ }
464
+ }
465
+ return this;
466
+ }
467
+
468
+ @JRubyMethod(name="empty?")
469
+ public IRubyObject empty_p(ThreadContext context) {
470
+ return common.empty_p(context, vector_or_seq);
471
+ }
472
+
473
+ @JRubyMethod(name={"eql?", "=="})
474
+ public IRubyObject equal_p(ThreadContext context, IRubyObject arg) {
475
+ if (arg.isNil()) return context.getRuntime().getFalse();
476
+ Object other_vector = null;
477
+ if (arg instanceof DiametricCollection) {
478
+ other_vector = ((DiametricCollection)arg).toJava();
479
+ } else if ((arg instanceof List) || (arg instanceof RubyArray)) {
480
+ other_vector = arg;
481
+ } else {
482
+ return context.getRuntime().getFalse();
483
+ }
484
+ try {
485
+ Var var = DiametricService.getFn("clojure.core", "=");
486
+ if ((Boolean)var.invoke(vector_or_seq, other_vector)) {
487
+ return context.getRuntime().getTrue();
488
+ } else {
489
+ return context.getRuntime().getFalse();
490
+ }
491
+ } catch (Throwable t) {
492
+ throw context.getRuntime().newRuntimeError(t.getMessage());
493
+ }
61
494
  }
62
495
 
63
- @JRubyMethod(name = "all?")
64
- public static IRubyObject all_p(ThreadContext context, IRubyObject self, final Block block) {
65
- return context.getRuntime().getNil();
496
+ @JRubyMethod(required=1, optional=1)
497
+ public IRubyObject fetch(ThreadContext context, IRubyObject args[], Block block) {
498
+ Long index = (Long)args[0].toJava(Long.class);
499
+ try {
500
+ Var var = DiametricService.getFn("clojure.core", "nth");
501
+ // counting vector size will be costly when the vector is way huge.
502
+ // allows to raise exception for negative or too big index
503
+ Object value = var.invoke(vector_or_seq, index);
504
+ return DiametricUtils.convertJavaToRuby(context, value);
505
+ } catch (Throwable t) {
506
+ if (t instanceof IndexOutOfBoundsException) {
507
+ return retryFetch(context, args, block, index);
508
+ }
509
+ throw context.getRuntime().newRuntimeError(t.getMessage());
510
+ }
66
511
  }
512
+
513
+ private IRubyObject retryFetch(ThreadContext context, IRubyObject[] args, Block block, Long index) {
514
+ // now, counts vector size and adjust the index
515
+ if (index > (long)getCount()) return handleError(context, args, block);
516
+ if (index < 0L) index += (long)getCount();
517
+ if (index < 0L) return handleError(context, args, block);
67
518
 
68
- @JRubyMethod(name = "any?")
69
- public static IRubyObject any_p(ThreadContext context, IRubyObject self, final Block block) {
70
- return context.getRuntime().getNil();
519
+ try {
520
+ Var var = DiametricService.getFn("clojure.core", "nth");
521
+ Object value = var.invoke(vector_or_seq, index);
522
+ return DiametricUtils.convertJavaToRuby(context, value);
523
+ } catch (Throwable t) {
524
+ if (t instanceof IndexOutOfBoundsException) {
525
+ return handleError(context, args, block);
526
+ }
527
+ throw context.getRuntime().newRuntimeError(t.getMessage());
528
+ }
71
529
  }
72
530
 
73
- @JRubyMethod
74
- public static IRubyObject chunk(ThreadContext context, IRubyObject self, final Block block) {
75
- return context.getRuntime().getNil();
531
+ private IRubyObject handleError(ThreadContext context, IRubyObject[] args, Block block) {
532
+ if (block.isGiven()) {
533
+ return block.yield(context, args[0]);
534
+ } else if (args.length == 2) {
535
+ return args[1];
536
+ } else {
537
+ throw context.getRuntime().newIndexError("Given index is out of vector size");
538
+ }
76
539
  }
77
540
 
78
541
  @JRubyMethod
79
- public static IRubyObject chunk(ThreadContext context, IRubyObject self, final IRubyObject initialState, final Block block) {
80
- return context.getRuntime().getNil();
542
+ public IRubyObject fill(ThreadContext context, Block block) {
543
+ throw context.getRuntime().newRuntimeError("Not supported. Data is a query result.");
81
544
  }
82
545
 
83
- @JRubyMethod
84
- public static IRubyObject collect(ThreadContext context, IRubyObject self, final Block block) {
85
- return context.getRuntime().getNil();
546
+ @JRubyMethod(required=1, optional=2)
547
+ public IRubyObject fill(ThreadContext context, IRubyObject args[], Block block) {
548
+ throw context.getRuntime().newRuntimeError("Not supported. Data is a query result.");
549
+ }
550
+
551
+ @JRubyMethod(name={"find_index", "index"})
552
+ public IRubyObject find_index(ThreadContext context, IRubyObject arg, Block unsed) {
553
+ Object java_obj = DiametricUtils.convertRubyToJava(context, arg);
554
+ int index = vector_or_seq.indexOf(java_obj);
555
+ if (index >= 0) {
556
+ return context.getRuntime().newFixnum(index);
557
+ } else {
558
+ return context.getRuntime().getNil();
559
+ }
86
560
  }
87
561
 
562
+ @JRubyMethod(name={"find_index", "index"})
563
+ public IRubyObject find_index(ThreadContext context, Block block) {
564
+ if (block.isGiven()) {
565
+ Iterator<Object> itr = vector_or_seq.iterator();
566
+ int index = 0;
567
+ while (itr.hasNext()) {
568
+ IRubyObject value = DiametricUtils.convertJavaToRuby(context, itr.next());
569
+ if (block.yield(context, value).isTrue()) {
570
+ return context.getRuntime().newFixnum(index);
571
+ }
572
+ index++;
573
+ }
574
+ return context.getRuntime().getNil();
575
+ } else {
576
+ return this;
577
+ }
578
+ }
579
+
88
580
  @JRubyMethod
89
- public static IRubyObject collect_concat(ThreadContext context, IRubyObject self, final Block block) {
90
- return context.getRuntime().getNil();
581
+ public IRubyObject first(ThreadContext context) {
582
+ return common.first(context, vector_or_seq);
91
583
  }
92
584
 
93
585
  @JRubyMethod
94
- public static IRubyObject count(ThreadContext context, IRubyObject self, final Block block) {
95
- return context.getRuntime().getNil();
586
+ public IRubyObject first(ThreadContext context, IRubyObject arg) {
587
+ if (!(arg instanceof RubyFixnum)) throw context.getRuntime().newArgumentError("argument should be a Fixnum");
588
+ Long n = (Long)arg.toJava(Long.class);
589
+ return common.first(context, n, vector_or_seq);
96
590
  }
97
591
 
98
592
  @JRubyMethod
99
- public static IRubyObject count(ThreadContext context, IRubyObject self, final IRubyObject methodArg, final Block block) {
100
- return context.getRuntime().getNil();
593
+ public IRubyObject flatten(ThreadContext context) {
594
+ throw context.getRuntime().newRuntimeError("Not yet supported. Might be implented later depends on datomic queries.");
101
595
  }
102
596
 
103
597
  @JRubyMethod
104
- public static IRubyObject cycle(ThreadContext context, IRubyObject self, final Block block) {
105
- return context.getRuntime().getNil();
598
+ public IRubyObject flatten(ThreadContext context, IRubyObject arg) {
599
+ throw context.getRuntime().newRuntimeError("Not yet supported. Might be implented later depends on datomic queries.");
106
600
  }
107
-
601
+
602
+ @JRubyMethod(name="flatten!")
603
+ public IRubyObject flatten_bang(ThreadContext context) {
604
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
605
+ }
606
+
607
+ @JRubyMethod(name="flatten!")
608
+ public IRubyObject flatten_bang(ThreadContext context, IRubyObject arg) {
609
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
610
+ }
611
+
612
+ @JRubyMethod(name="frozen?")
613
+ public RubyBoolean frozen_p(ThreadContext context) {
614
+ return (RubyBoolean)context.getRuntime().getTrue();
615
+ }
616
+
108
617
  @JRubyMethod
109
- public static IRubyObject cycle(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
110
- return context.getRuntime().getNil();
618
+ public IRubyObject hash(ThreadContext context) {
619
+ return common.hash(context, vector_or_seq);
111
620
  }
112
-
621
+
622
+ @JRubyMethod(name="include?")
623
+ public IRubyObject include_p(ThreadContext context, IRubyObject arg) {
624
+ Var include_p_fn = null;
625
+ if (DiametricService.fnMap.containsKey("include?")) {
626
+ include_p_fn = DiametricService.fnMap.get("include?");
627
+ } else {
628
+ Var var = DiametricService.getFn("clojure.core", "load-string");
629
+ include_p_fn = (Var)var.invoke("(defn include? [v array] (some (partial = v) array))");
630
+ DiametricService.fnMap.put("include?", include_p_fn);
631
+ }
632
+ Object java_object = DiametricUtils.convertRubyToJava(context, arg);
633
+ try {
634
+ Object result = include_p_fn.invoke(java_object, vector_or_seq);
635
+ if ((result instanceof Boolean) && (Boolean)result) {
636
+ return context.getRuntime().getTrue();
637
+ } else {
638
+ return context.getRuntime().getFalse();
639
+ }
640
+ } catch (Throwable t) {
641
+ throw context.getRuntime().newRuntimeError(t.getMessage());
642
+ }
643
+ }
644
+
645
+ @JRubyMethod(required=2, rest=true)
646
+ public IRubyObject insert(ThreadContext context, IRubyObject[] args) {
647
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
648
+ }
649
+
113
650
  @JRubyMethod
114
- public static IRubyObject detect(ThreadContext context, IRubyObject self, final Block block) {
115
- return context.getRuntime().getNil();
651
+ public IRubyObject join(ThreadContext context) {
652
+ try {
653
+ Var var = DiametricService.getFn("clojure.string", "join");
654
+ return context.getRuntime().newString((String)var.invoke(vector_or_seq));
655
+ } catch (Throwable t) {
656
+ throw context.getRuntime().newRuntimeError(t.getMessage());
657
+ }
116
658
  }
117
-
659
+
118
660
  @JRubyMethod
119
- public static IRubyObject detect(ThreadContext context, IRubyObject self, IRubyObject ifnone, final Block block) {
120
- return context.getRuntime().getNil();
661
+ public IRubyObject join(ThreadContext context, IRubyObject arg) {
662
+ if (arg.isNil()) {
663
+ return join(context);
664
+ } else if (arg instanceof RubyString) {
665
+ try {
666
+ String separator = (String)arg.toJava(String.class);
667
+ Var var = DiametricService.getFn("clojure.string", "join");
668
+ return context.getRuntime().newString((String)var.invoke(separator, vector_or_seq));
669
+ } catch (Throwable t) {
670
+ throw context.getRuntime().newRuntimeError(t.getMessage());
671
+ }
672
+ }
673
+ return context.getRuntime().getNil();
121
674
  }
122
-
675
+
676
+ @JRubyMethod(name={"keep_if", "select!"})
677
+ public IRubyObject keep_if(ThreadContext context, Block block) {
678
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
679
+ }
680
+
123
681
  @JRubyMethod
124
- public static IRubyObject drop(ThreadContext context, IRubyObject self, IRubyObject n, final Block block) {
125
- return context.getRuntime().getNil();
682
+ public IRubyObject last(ThreadContext context) {
683
+ try {
684
+ Var var = DiametricService.getFn("clojure.core", "last");
685
+ return DiametricUtils.convertJavaToRuby(context, var.invoke(vector_or_seq));
686
+ } catch (Throwable t) {
687
+ throw context.getRuntime().newRuntimeError(t.getMessage());
688
+ }
126
689
  }
127
-
690
+
128
691
  @JRubyMethod
129
- public static IRubyObject drop_while(ThreadContext context, IRubyObject self, final Block block) {
130
- return context.getRuntime().getNil();
692
+ public IRubyObject last(ThreadContext context, IRubyObject arg) {
693
+ if (!(arg instanceof RubyFixnum)) {
694
+ throw context.getRuntime().newArgumentError("Argument should be a Fixnum");
695
+ }
696
+ if (vector_or_seq.isEmpty()) return context.getRuntime().newEmptyArray();
697
+ Long n = (Long)arg.toJava(Long.class);
698
+ try {
699
+ Var var = DiametricService.getFn("clojure.core", "take-last");
700
+ return DiametricUtils.convertJavaToRuby(context, var.invoke(n, vector_or_seq));
701
+ } catch (Throwable t) {
702
+ throw context.getRuntime().newRuntimeError(t.getMessage());
703
+ }
131
704
  }
132
-
705
+
133
706
  @JRubyMethod
134
- public static IRubyObject each_cons(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
135
- return context.getRuntime().getNil();
707
+ public IRubyObject pack(ThreadContext context, IRubyObject arg) {
708
+ throw context.getRuntime().newRuntimeError("Not supported. Perhaps, doesn't make sense for query result.");
136
709
  }
137
-
710
+
711
+ @JRubyMethod
712
+ public IRubyObject permutation(ThreadContext context, IRubyObject arg, Block block) {
713
+ throw context.getRuntime().newRuntimeError("Not supported. Perhaps, doesn't make sense for query result.");
714
+ }
715
+
716
+ @JRubyMethod
717
+ public IRubyObject permutation(ThreadContext context, Block block) {
718
+ throw context.getRuntime().newRuntimeError("Not supported. Perhaps, doesn't make sense for query result.");
719
+ }
720
+
721
+ @JRubyMethod
722
+ public IRubyObject pop(ThreadContext context) {
723
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
724
+ }
725
+
726
+ @JRubyMethod
727
+ public IRubyObject pop(ThreadContext context, IRubyObject arg) {
728
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
729
+ }
730
+
138
731
  @JRubyMethod(rest = true)
139
- public static IRubyObject each_entry(ThreadContext context, final IRubyObject self, final IRubyObject[] args, final Block block) {
140
- return context.getRuntime().getNil();
732
+ public IRubyObject product(ThreadContext context, IRubyObject[] args, Block block) {
733
+ throw context.getRuntime().newRuntimeError("Not supported. Perhaps, doesn't make sense for query result.");
141
734
  }
142
-
735
+
143
736
  @JRubyMethod
144
- public static IRubyObject each_slice(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
145
- return context.getRuntime().getNil();
737
+ public IRubyObject replace(ThreadContext context, IRubyObject arg) {
738
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
739
+ }
740
+
741
+ @JRubyMethod(rest = true)
742
+ public IRubyObject push(ThreadContext context, IRubyObject[] arg) {
743
+ throw context.getRuntime().newRuntimeError("Not supported. Data is immutable.");
744
+ }
745
+
746
+ @JRubyMethod
747
+ public IRubyObject rassoc(ThreadContext context, IRubyObject arg) {
748
+ throw context.getRuntime().newRuntimeError("Not yet supported. Might be implented later depends on datomic queries.");
749
+ }
750
+
751
+ private int getCount() {
752
+ if (count == null) {
753
+ Var var = DiametricService.getFn("clojure.core", "count");
754
+ count = (Integer)var.invoke(vector_or_seq);
755
+ }
756
+ return count;
757
+ }
758
+
759
+ @JRubyMethod(name={"length", "size"})
760
+ public IRubyObject size(ThreadContext context) {
761
+ try {
762
+ return context.getRuntime().newFixnum(getCount());
763
+ } catch (Throwable t) {
764
+ throw context.getRuntime().newRuntimeError(t.getMessage());
765
+ }
766
+ }
767
+
768
+ @JRubyMethod(name={"to_a", "to_ary"})
769
+ public IRubyObject to_a(ThreadContext context) {
770
+ return this;
771
+ }
772
+
773
+ @JRubyMethod(name={"to_s", "inspect"})
774
+ public IRubyObject to_s(ThreadContext context) {
775
+ return common.to_s(context, vector_or_seq);
146
776
  }
147
777
  }