nql 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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