module NQL grammar Syntax rule expression boolean / primary end rule boolean left:primary space coordinator:coordinator space right:expression { def to_ransack group = {g: [{m: coordinator.to_ransack}]} [left, right].each do |side| if side.is_node?(:boolean) group[:g][0].merge! side.to_ransack else group[:g][0][:c] ||= [] group[:g][0][:c] << side.to_ransack end end group end def is_node?(node_type) node_type.to_sym == :boolean end } end rule primary (space comparison space / '(' space expression space ')') { def to_ransack detect_node.to_ransack end def detect_node self.send %w(comparison expression).detect { |m| self.respond_to? m } end def is_node?(node_type) detect_node.is_node?(node_type) end } end rule coordinator ('|' / '&') { def to_ransack coordinators = {'|' => 'or', '&' => 'and'} coordinators[text_value] end } end rule comparison variable:alphanumeric space comparator:comparator space value:text { def to_ransack hash = {a: {'0' => {name: self.variable.text_value.gsub('.', '_')}}, p: self.comparator.to_ransack, v: {'0' => {value: self.value.text_value}}} hash = {c: [hash]} if !parent || !parent.parent || text_value == parent.parent.text_value hash end def is_node?(node_type) node_type.to_sym == :comparison end } end rule comparator ('=' / '!=' / '>' / '>=' / '<' / '<=' / ':' / '~')+ { def to_ransack comparators = { '=' => 'eq', '!=' => 'not_eq', '>' => 'gt', '>=' => 'gteq', '<' => 'lt', '<=' => 'lteq', ':' => 'cont', '~' => 'matches' } comparators[text_value] end } end rule text (alphanumeric / utf8 / symbol)+ (space (alphanumeric / utf8 / symbol)+)* end rule alphanumeric [a-zA-Z0-9_.]+ end rule space ' '* end rule symbol [><=+-\/\\@#$%!?:] end rule utf8 [\u00c0\u00c1\u00c2\u00c3\u00c4\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d9\u00da\u00db\u00dc\u00e0\u00e1\u00e2\u00e3\u00e4\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f9\u00fa\u00fb\u00fc] end end end