Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

New Shorthands #8

Open
wants to merge 3 commits into from

2 participants

@tyok

In regard to #7. Please give your thought on this.

@igrigorik
Owner

Hi Mohammad. The implementation itself makes sense, and as you highlighted in the ticket.. extending the grammar is pretty straight forward. If this is a syntax extension that you need for your project, then it definitely makes sense.

Having said that, I'm a little hesitant to merge this because adding / and & into the syntax also means you have to be much more careful in your queries - these characters become reserved, and we don't really provide an escape mechanism. Meaning, if someone actually has a string like "a & b" then they'll run into issues. The idea behind explicitly defining upcase variants was to minimize these collisions (AND, and OR are less likely collision candidates).

@tyok

Thanks for your feedback. I tried to play with such queries, and it turns out the the parser implementation is quite robust. I can escape a logical keyword by wrapping it around quotes:

TextQuery.new("a 'OR' b").match? "a"
=> false

TextQuery.new("a 'OR' b").match? "a OR b"
=> true

For my needs, this is sufficient. Might not for yours, though. You might still be interested in the behavior shown in my spec above, since it should be present in your master branch too. Maybe you want to document, exploit, or fix that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 19, 2011
  1. @tyok

    evaluate '/' as OR

    tyok authored
  2. @tyok

    evaluate '&' as AND

    tyok authored
Commits on Sep 20, 2011
  1. @tyok
This page is out of date. Refresh to see the latest.
Showing with 53 additions and 19 deletions.
  1. +2 −2 lib/textquery/textquery_grammar.treetop
  2. +51 −17 spec/textquery_spec.rb
View
4 lib/textquery/textquery_grammar.treetop
@@ -27,7 +27,7 @@ grammar TextQueryGrammar
end
rule binary
- 'AND' {
+ ('&' /'AND') {
def eval(a,b)
a && b
end
@@ -37,7 +37,7 @@ grammar TextQueryGrammar
end
}
/
- 'OR' {
+ ('/' / 'OR') {
def eval(a,b)
a || b
end
View
68 spec/textquery_spec.rb
@@ -31,32 +31,40 @@ def parse(input)
end
it "should accept logical AND" do
- parse("a AND b").eval("c").should be_false
- parse("a AND b").eval("a").should be_false
- parse("a AND b").eval("b").should be_false
+ %w[& AND].each do |_and|
+ parse("a #{_and} b").eval("c").should be_false
+ parse("a #{_and} b").eval("a").should be_false
+ parse("a #{_and} b").eval("b").should be_false
- parse("a AND b").eval("a b").should be_true
- parse("a AND b").eval("a c b").should be_true
+ parse("a #{_and} b").eval("a b").should be_true
+ parse("a #{_and} b").eval("a c b").should be_true
+ end
end
it "should accept logical OR" do
- parse("a OR b").eval("c").should be_false
- parse("a OR b").eval("a").should be_true
- parse("a OR b").eval("b").should be_true
+ %w[/ OR].each do |_or|
+ parse("a #{_or} b").eval("c").should be_false
+ parse("a #{_or} b").eval("a").should be_true
+ parse("a #{_or} b").eval("b").should be_true
- parse("a OR b").eval("a b").should be_true
- parse("a OR b").eval("a c b").should be_true
+ parse("a #{_or} b").eval("a b").should be_true
+ parse("a #{_or} b").eval("a c b").should be_true
+ end
end
it "should give precedence to AND" do
# a AND (b OR c) == a AND b OR c
- parse("a AND b OR c").eval("a b c").should be_true
- parse("a AND b OR c").eval("a b").should be_true
- parse("a AND b OR c").eval("a c").should be_true
-
- parse("a AND b OR c").eval("b c").should be_false
- parse("a AND b OR c").eval("c").should be_false
- parse("a AND b OR c").eval("b").should be_false
+ %w[& AND].each do |_and|
+ %w[/ OR].each do |_or|
+ parse("a #{_and} b #{_or} c").eval("a b c").should be_true
+ parse("a #{_and} b #{_or} c").eval("a b").should be_true
+ parse("a #{_and} b #{_or} c").eval("a c").should be_true
+
+ parse("a #{_and} b #{_or} c").eval("b c").should be_false
+ parse("a #{_and} b #{_or} c").eval("c").should be_false
+ parse("a #{_and} b #{_or} c").eval("b").should be_false
+ end
+ end
end
it "should accept logical NOT" do
@@ -228,6 +236,32 @@ def parse(input)
TextQuery.new("a AND CD", :ignorecase => false).match?("A b cD").should be_false
end
+ it "should provide a way to use reserved keyword as regular string in query" do
+ %w[AND &].each do |_and|
+ TextQuery.new("a '#{_and}' b").match?("a b").should be_false
+ TextQuery.new("a '#{_and}' b").match?("a b #{_and}").should be_true
+
+ TextQuery.new("'a #{_and} b'").match?("a b").should be_false
+ TextQuery.new("'a #{_and} b'").match?("a #{_and} b").should be_true
+ end
+
+ %w[OR /].each do |_or|
+ TextQuery.new("a '#{_or}' b").match?("a").should be_false
+ TextQuery.new("a '#{_or}' b").match?("a b #{_or}").should be_true
+
+ TextQuery.new("'a #{_or} b'").match?("a b").should be_false
+ TextQuery.new("'a #{_or} b'").match?("a #{_or} b").should be_true
+ end
+
+ %w[NOT -].each do |_not|
+ TextQuery.new("'#{_not}' a").match?("b").should be_false
+ TextQuery.new("'#{_not}' a").match?("a #{_not}").should be_true
+
+ TextQuery.new("'#{_not} a'").match?("b").should be_false
+ TextQuery.new("'#{_not} a'").match?("#{_not} a").should be_true
+ end
+ end
+
context 'delimiters' do
it 'should default to space delimiter' do
TextQuery.new("a").match?("a b").should be_true
Something went wrong with that request. Please try again.