nql 0.0.1

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.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nql.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 gabriel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # NQL
2
+
3
+ Natural Query Language built on top of ActiveRecord and Ransack
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'nql'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install nql
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,15 @@
1
+ require 'treetop'
2
+ require 'active_record'
3
+ require 'active_support/all'
4
+ require 'ransack'
5
+
6
+ require 'nql/version'
7
+ require 'nql/grammar'
8
+
9
+ module NQL
10
+
11
+ def self.to_ransack(query)
12
+ SyntaxParser.new.parse(query).to_ransack
13
+ end
14
+
15
+ end
@@ -0,0 +1,761 @@
1
+ # Autogenerated from a Treetop grammar. Edits may be lost.
2
+
3
+
4
+ module NQL
5
+ module Syntax
6
+ include Treetop::Runtime
7
+
8
+ def root
9
+ @root ||= :expression
10
+ end
11
+
12
+ def _nt_expression
13
+ start_index = index
14
+ if node_cache[:expression].has_key?(index)
15
+ cached = node_cache[:expression][index]
16
+ if cached
17
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
18
+ @index = cached.interval.end
19
+ end
20
+ return cached
21
+ end
22
+
23
+ i0 = index
24
+ r1 = _nt_boolean
25
+ if r1
26
+ r0 = r1
27
+ else
28
+ r2 = _nt_primary
29
+ if r2
30
+ r0 = r2
31
+ else
32
+ @index = i0
33
+ r0 = nil
34
+ end
35
+ end
36
+
37
+ node_cache[:expression][start_index] = r0
38
+
39
+ r0
40
+ end
41
+
42
+ module Boolean0
43
+ def left
44
+ elements[0]
45
+ end
46
+
47
+ def space1
48
+ elements[1]
49
+ end
50
+
51
+ def coordinator
52
+ elements[2]
53
+ end
54
+
55
+ def space2
56
+ elements[3]
57
+ end
58
+
59
+ def right
60
+ elements[4]
61
+ end
62
+ end
63
+
64
+ module Boolean1
65
+ def to_ransack
66
+ group = {'g' => [{'m' => coordinator.to_ransack}]}
67
+
68
+ [left, right].each do |side|
69
+ if side.is_node?(:boolean)
70
+ group['g'][0].merge! side.to_ransack
71
+ else
72
+ group['g'][0]['c'] ||= []
73
+ group['g'][0]['c'] << side.to_ransack
74
+ end
75
+ end
76
+
77
+ group
78
+ end
79
+
80
+ def is_node?(node_type)
81
+ node_type.to_sym == :boolean
82
+ end
83
+ end
84
+
85
+ def _nt_boolean
86
+ start_index = index
87
+ if node_cache[:boolean].has_key?(index)
88
+ cached = node_cache[:boolean][index]
89
+ if cached
90
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
91
+ @index = cached.interval.end
92
+ end
93
+ return cached
94
+ end
95
+
96
+ i0, s0 = index, []
97
+ r1 = _nt_primary
98
+ s0 << r1
99
+ if r1
100
+ r2 = _nt_space
101
+ s0 << r2
102
+ if r2
103
+ r3 = _nt_coordinator
104
+ s0 << r3
105
+ if r3
106
+ r4 = _nt_space
107
+ s0 << r4
108
+ if r4
109
+ r5 = _nt_expression
110
+ s0 << r5
111
+ end
112
+ end
113
+ end
114
+ end
115
+ if s0.last
116
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
117
+ r0.extend(Boolean0)
118
+ r0.extend(Boolean1)
119
+ else
120
+ @index = i0
121
+ r0 = nil
122
+ end
123
+
124
+ node_cache[:boolean][start_index] = r0
125
+
126
+ r0
127
+ end
128
+
129
+ module Primary0
130
+ def space1
131
+ elements[0]
132
+ end
133
+
134
+ def comparison
135
+ elements[1]
136
+ end
137
+
138
+ def space2
139
+ elements[2]
140
+ end
141
+ end
142
+
143
+ module Primary1
144
+ def space1
145
+ elements[1]
146
+ end
147
+
148
+ def expression
149
+ elements[2]
150
+ end
151
+
152
+ def space2
153
+ elements[3]
154
+ end
155
+
156
+ end
157
+
158
+ module Primary2
159
+ def to_ransack
160
+ detect_node.to_ransack
161
+ end
162
+
163
+ def detect_node
164
+ self.send %w(comparison expression).detect { |m| self.respond_to? m }
165
+ end
166
+
167
+ def is_node?(node_type)
168
+ detect_node.is_node?(node_type)
169
+ end
170
+ end
171
+
172
+ def _nt_primary
173
+ start_index = index
174
+ if node_cache[:primary].has_key?(index)
175
+ cached = node_cache[:primary][index]
176
+ if cached
177
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
178
+ @index = cached.interval.end
179
+ end
180
+ return cached
181
+ end
182
+
183
+ i0 = index
184
+ i1, s1 = index, []
185
+ r2 = _nt_space
186
+ s1 << r2
187
+ if r2
188
+ r3 = _nt_comparison
189
+ s1 << r3
190
+ if r3
191
+ r4 = _nt_space
192
+ s1 << r4
193
+ end
194
+ end
195
+ if s1.last
196
+ r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
197
+ r1.extend(Primary0)
198
+ else
199
+ @index = i1
200
+ r1 = nil
201
+ end
202
+ if r1
203
+ r0 = r1
204
+ r0.extend(Primary2)
205
+ else
206
+ i5, s5 = index, []
207
+ if has_terminal?('(', false, index)
208
+ r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
209
+ @index += 1
210
+ else
211
+ terminal_parse_failure('(')
212
+ r6 = nil
213
+ end
214
+ s5 << r6
215
+ if r6
216
+ r7 = _nt_space
217
+ s5 << r7
218
+ if r7
219
+ r8 = _nt_expression
220
+ s5 << r8
221
+ if r8
222
+ r9 = _nt_space
223
+ s5 << r9
224
+ if r9
225
+ if has_terminal?(')', false, index)
226
+ r10 = instantiate_node(SyntaxNode,input, index...(index + 1))
227
+ @index += 1
228
+ else
229
+ terminal_parse_failure(')')
230
+ r10 = nil
231
+ end
232
+ s5 << r10
233
+ end
234
+ end
235
+ end
236
+ end
237
+ if s5.last
238
+ r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
239
+ r5.extend(Primary1)
240
+ else
241
+ @index = i5
242
+ r5 = nil
243
+ end
244
+ if r5
245
+ r0 = r5
246
+ r0.extend(Primary2)
247
+ else
248
+ @index = i0
249
+ r0 = nil
250
+ end
251
+ end
252
+
253
+ node_cache[:primary][start_index] = r0
254
+
255
+ r0
256
+ end
257
+
258
+ module Coordinator0
259
+ def to_ransack
260
+ coordinators = {'|' => 'or', '&' => 'and'}
261
+ coordinators[text_value]
262
+ end
263
+ end
264
+
265
+ def _nt_coordinator
266
+ start_index = index
267
+ if node_cache[:coordinator].has_key?(index)
268
+ cached = node_cache[:coordinator][index]
269
+ if cached
270
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
271
+ @index = cached.interval.end
272
+ end
273
+ return cached
274
+ end
275
+
276
+ i0 = index
277
+ if has_terminal?('|', false, index)
278
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
279
+ @index += 1
280
+ else
281
+ terminal_parse_failure('|')
282
+ r1 = nil
283
+ end
284
+ if r1
285
+ r0 = r1
286
+ r0.extend(Coordinator0)
287
+ else
288
+ if has_terminal?('&', false, index)
289
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
290
+ @index += 1
291
+ else
292
+ terminal_parse_failure('&')
293
+ r2 = nil
294
+ end
295
+ if r2
296
+ r0 = r2
297
+ r0.extend(Coordinator0)
298
+ else
299
+ @index = i0
300
+ r0 = nil
301
+ end
302
+ end
303
+
304
+ node_cache[:coordinator][start_index] = r0
305
+
306
+ r0
307
+ end
308
+
309
+ module Comparison0
310
+ def variable
311
+ elements[0]
312
+ end
313
+
314
+ def space1
315
+ elements[1]
316
+ end
317
+
318
+ def comparator
319
+ elements[2]
320
+ end
321
+
322
+ def space2
323
+ elements[3]
324
+ end
325
+
326
+ def value
327
+ elements[4]
328
+ end
329
+ end
330
+
331
+ module Comparison1
332
+ def to_ransack
333
+ hash = {'a' => {'0' => {'name' => self.variable.text_value.gsub('.', '_')}}, 'p' => self.comparator.to_ransack, 'v' => {'0' => {'value' => self.value.text_value}}}
334
+ hash = {'c' => [hash]} if !parent || !parent.parent || text_value == parent.parent.text_value
335
+ hash
336
+ end
337
+
338
+ def is_node?(node_type)
339
+ node_type.to_sym == :comparison
340
+ end
341
+ end
342
+
343
+ def _nt_comparison
344
+ start_index = index
345
+ if node_cache[:comparison].has_key?(index)
346
+ cached = node_cache[:comparison][index]
347
+ if cached
348
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
349
+ @index = cached.interval.end
350
+ end
351
+ return cached
352
+ end
353
+
354
+ i0, s0 = index, []
355
+ r1 = _nt_alphanumeric
356
+ s0 << r1
357
+ if r1
358
+ r2 = _nt_space
359
+ s0 << r2
360
+ if r2
361
+ r3 = _nt_comparator
362
+ s0 << r3
363
+ if r3
364
+ r4 = _nt_space
365
+ s0 << r4
366
+ if r4
367
+ r5 = _nt_text
368
+ s0 << r5
369
+ end
370
+ end
371
+ end
372
+ end
373
+ if s0.last
374
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
375
+ r0.extend(Comparison0)
376
+ r0.extend(Comparison1)
377
+ else
378
+ @index = i0
379
+ r0 = nil
380
+ end
381
+
382
+ node_cache[:comparison][start_index] = r0
383
+
384
+ r0
385
+ end
386
+
387
+ module Comparator0
388
+ def to_ransack
389
+ comparators = {
390
+ '=' => 'eq',
391
+ '!=' => 'not_eq',
392
+ '>' => 'gt',
393
+ '>=' => 'gteq',
394
+ '<' => 'lt',
395
+ '<=' => 'lteq',
396
+ '%' => 'cont'
397
+ }
398
+ comparators[text_value]
399
+ end
400
+ end
401
+
402
+ def _nt_comparator
403
+ start_index = index
404
+ if node_cache[:comparator].has_key?(index)
405
+ cached = node_cache[:comparator][index]
406
+ if cached
407
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
408
+ @index = cached.interval.end
409
+ end
410
+ return cached
411
+ end
412
+
413
+ s0, i0 = [], index
414
+ loop do
415
+ i1 = index
416
+ if has_terminal?('=', false, index)
417
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
418
+ @index += 1
419
+ else
420
+ terminal_parse_failure('=')
421
+ r2 = nil
422
+ end
423
+ if r2
424
+ r1 = r2
425
+ else
426
+ if has_terminal?('!=', false, index)
427
+ r3 = instantiate_node(SyntaxNode,input, index...(index + 2))
428
+ @index += 2
429
+ else
430
+ terminal_parse_failure('!=')
431
+ r3 = nil
432
+ end
433
+ if r3
434
+ r1 = r3
435
+ else
436
+ if has_terminal?('>', false, index)
437
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
438
+ @index += 1
439
+ else
440
+ terminal_parse_failure('>')
441
+ r4 = nil
442
+ end
443
+ if r4
444
+ r1 = r4
445
+ else
446
+ if has_terminal?('>=', false, index)
447
+ r5 = instantiate_node(SyntaxNode,input, index...(index + 2))
448
+ @index += 2
449
+ else
450
+ terminal_parse_failure('>=')
451
+ r5 = nil
452
+ end
453
+ if r5
454
+ r1 = r5
455
+ else
456
+ if has_terminal?('<', false, index)
457
+ r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
458
+ @index += 1
459
+ else
460
+ terminal_parse_failure('<')
461
+ r6 = nil
462
+ end
463
+ if r6
464
+ r1 = r6
465
+ else
466
+ if has_terminal?('<=', false, index)
467
+ r7 = instantiate_node(SyntaxNode,input, index...(index + 2))
468
+ @index += 2
469
+ else
470
+ terminal_parse_failure('<=')
471
+ r7 = nil
472
+ end
473
+ if r7
474
+ r1 = r7
475
+ else
476
+ if has_terminal?('%', false, index)
477
+ r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
478
+ @index += 1
479
+ else
480
+ terminal_parse_failure('%')
481
+ r8 = nil
482
+ end
483
+ if r8
484
+ r1 = r8
485
+ else
486
+ @index = i1
487
+ r1 = nil
488
+ end
489
+ end
490
+ end
491
+ end
492
+ end
493
+ end
494
+ end
495
+ if r1
496
+ s0 << r1
497
+ else
498
+ break
499
+ end
500
+ end
501
+ if s0.empty?
502
+ @index = i0
503
+ r0 = nil
504
+ else
505
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
506
+ r0.extend(Comparator0)
507
+ end
508
+
509
+ node_cache[:comparator][start_index] = r0
510
+
511
+ r0
512
+ end
513
+
514
+ module Text0
515
+ def space
516
+ elements[0]
517
+ end
518
+
519
+ end
520
+
521
+ module Text1
522
+ end
523
+
524
+ def _nt_text
525
+ start_index = index
526
+ if node_cache[:text].has_key?(index)
527
+ cached = node_cache[:text][index]
528
+ if cached
529
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
530
+ @index = cached.interval.end
531
+ end
532
+ return cached
533
+ end
534
+
535
+ i0, s0 = index, []
536
+ s1, i1 = [], index
537
+ loop do
538
+ i2 = index
539
+ r3 = _nt_alphanumeric
540
+ if r3
541
+ r2 = r3
542
+ else
543
+ r4 = _nt_utf8
544
+ if r4
545
+ r2 = r4
546
+ else
547
+ r5 = _nt_symbol
548
+ if r5
549
+ r2 = r5
550
+ else
551
+ @index = i2
552
+ r2 = nil
553
+ end
554
+ end
555
+ end
556
+ if r2
557
+ s1 << r2
558
+ else
559
+ break
560
+ end
561
+ end
562
+ if s1.empty?
563
+ @index = i1
564
+ r1 = nil
565
+ else
566
+ r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
567
+ end
568
+ s0 << r1
569
+ if r1
570
+ s6, i6 = [], index
571
+ loop do
572
+ i7, s7 = index, []
573
+ r8 = _nt_space
574
+ s7 << r8
575
+ if r8
576
+ s9, i9 = [], index
577
+ loop do
578
+ i10 = index
579
+ r11 = _nt_alphanumeric
580
+ if r11
581
+ r10 = r11
582
+ else
583
+ r12 = _nt_utf8
584
+ if r12
585
+ r10 = r12
586
+ else
587
+ r13 = _nt_symbol
588
+ if r13
589
+ r10 = r13
590
+ else
591
+ @index = i10
592
+ r10 = nil
593
+ end
594
+ end
595
+ end
596
+ if r10
597
+ s9 << r10
598
+ else
599
+ break
600
+ end
601
+ end
602
+ if s9.empty?
603
+ @index = i9
604
+ r9 = nil
605
+ else
606
+ r9 = instantiate_node(SyntaxNode,input, i9...index, s9)
607
+ end
608
+ s7 << r9
609
+ end
610
+ if s7.last
611
+ r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
612
+ r7.extend(Text0)
613
+ else
614
+ @index = i7
615
+ r7 = nil
616
+ end
617
+ if r7
618
+ s6 << r7
619
+ else
620
+ break
621
+ end
622
+ end
623
+ r6 = instantiate_node(SyntaxNode,input, i6...index, s6)
624
+ s0 << r6
625
+ end
626
+ if s0.last
627
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
628
+ r0.extend(Text1)
629
+ else
630
+ @index = i0
631
+ r0 = nil
632
+ end
633
+
634
+ node_cache[:text][start_index] = r0
635
+
636
+ r0
637
+ end
638
+
639
+ def _nt_alphanumeric
640
+ start_index = index
641
+ if node_cache[:alphanumeric].has_key?(index)
642
+ cached = node_cache[:alphanumeric][index]
643
+ if cached
644
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
645
+ @index = cached.interval.end
646
+ end
647
+ return cached
648
+ end
649
+
650
+ s0, i0 = [], index
651
+ loop do
652
+ if has_terminal?('\G[a-zA-Z0-9_.]', true, index)
653
+ r1 = true
654
+ @index += 1
655
+ else
656
+ r1 = nil
657
+ end
658
+ if r1
659
+ s0 << r1
660
+ else
661
+ break
662
+ end
663
+ end
664
+ if s0.empty?
665
+ @index = i0
666
+ r0 = nil
667
+ else
668
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
669
+ end
670
+
671
+ node_cache[:alphanumeric][start_index] = r0
672
+
673
+ r0
674
+ end
675
+
676
+ def _nt_space
677
+ start_index = index
678
+ if node_cache[:space].has_key?(index)
679
+ cached = node_cache[:space][index]
680
+ if cached
681
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
682
+ @index = cached.interval.end
683
+ end
684
+ return cached
685
+ end
686
+
687
+ s0, i0 = [], index
688
+ loop do
689
+ if has_terminal?(' ', false, index)
690
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
691
+ @index += 1
692
+ else
693
+ terminal_parse_failure(' ')
694
+ r1 = nil
695
+ end
696
+ if r1
697
+ s0 << r1
698
+ else
699
+ break
700
+ end
701
+ end
702
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
703
+
704
+ node_cache[:space][start_index] = r0
705
+
706
+ r0
707
+ end
708
+
709
+ def _nt_symbol
710
+ start_index = index
711
+ if node_cache[:symbol].has_key?(index)
712
+ cached = node_cache[:symbol][index]
713
+ if cached
714
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
715
+ @index = cached.interval.end
716
+ end
717
+ return cached
718
+ end
719
+
720
+ if has_terminal?('\G[><=+-\\/\\\\@#$%!?:]', true, index)
721
+ r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
722
+ @index += 1
723
+ else
724
+ r0 = nil
725
+ end
726
+
727
+ node_cache[:symbol][start_index] = r0
728
+
729
+ r0
730
+ end
731
+
732
+ def _nt_utf8
733
+ start_index = index
734
+ if node_cache[:utf8].has_key?(index)
735
+ cached = node_cache[:utf8][index]
736
+ if cached
737
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
738
+ @index = cached.interval.end
739
+ end
740
+ return cached
741
+ end
742
+
743
+ if has_terminal?('\G[\\u00c1\\u00c0\\u00c9\\u00c8\\u00cd\\u00cc\\u00d3\\u00d2\\u00da\\u00d9\\u00dc\\u00d1\\u00c7\\u00e1\\u00e0\\u00e9\\u00e8\\u00ed\\u00ec\\u00f3\\u00f2\\u00fa\\u00f9\\u00fc\\u00f1\\u00e7]', true, index)
744
+ r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
745
+ @index += 1
746
+ else
747
+ r0 = nil
748
+ end
749
+
750
+ node_cache[:utf8][start_index] = r0
751
+
752
+ r0
753
+ end
754
+
755
+ end
756
+
757
+ class SyntaxParser < Treetop::Runtime::CompiledParser
758
+ include Syntax
759
+ end
760
+
761
+ end