wherewolf 0.1.0 → 0.2.0
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.
- data/Gemfile.lock +1 -1
- data/README.rdoc +70 -27
- data/Rakefile +3 -3
- data/lib/wherewolf.rb +1 -0
- data/lib/wherewolf/parse_error.rb +20 -0
- data/lib/wherewolf/parser.rb +4 -2
- data/lib/wherewolf/processor.rb +11 -3
- data/test/parse_error_test.rb +9 -0
- data/test/parser_test.rb +19 -0
- data/test/processor_test.rb +40 -0
- data/wherewolf.gemspec +5 -3
- metadata +31 -29
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -1,30 +1,32 @@
|
|
1
1
|
= wherewolf
|
2
2
|
|
3
|
+
Makes adding filtering and searching to your REST API crazy easy.
|
4
|
+
|
3
5
|
== Problem
|
4
6
|
|
5
7
|
Most RESTful APIs expose a "/index" endpoint that return all of objects at a given endpoint. That is fine until you need the ability to filter them.
|
6
8
|
|
7
9
|
Consider the following scenario:
|
8
10
|
|
9
|
-
/
|
11
|
+
/players.json
|
10
12
|
|
11
|
-
But what if I want only
|
13
|
+
But what if I want only players that are active? Most developers would simply add a query parameter like so:
|
12
14
|
|
13
|
-
/
|
15
|
+
/players.json?active=true
|
14
16
|
|
15
|
-
Ok, now what if you only want
|
17
|
+
Ok, now what if you only want players capped after the first of January 2012? Maybe:
|
16
18
|
|
17
|
-
/
|
19
|
+
/players.json?first_cap=2012-01-01
|
18
20
|
|
19
21
|
Yeah, great - but it doesn't really scale. Wouldn't if be better if we could do something like this?
|
20
22
|
|
21
|
-
/
|
23
|
+
/players.json?where=active%20%3D%20true%20%26%26%20first_cap%20%3E%3D%202012-01-01
|
22
24
|
|
23
|
-
Ok, it doesn't read amazingly, but this is an API, so encoding that stuff is trivial for the client. For those of you that doesn't speak URI-
|
25
|
+
Ok, it doesn't read amazingly, but this is an API, so encoding that stuff is trivial for the client. For those of you that doesn't speak URI-encoded string that is the same as:
|
24
26
|
|
25
|
-
active = true &&
|
27
|
+
active = true && first_cap >= 2012-01-01
|
26
28
|
|
27
|
-
Wherewolf will take that string and converts it in to
|
29
|
+
Wherewolf will take that string and converts it in to ARel, so your clients can run arbitary queries against your API.
|
28
30
|
|
29
31
|
== Get started
|
30
32
|
|
@@ -32,29 +34,70 @@ The easiest way is to use Bundler:
|
|
32
34
|
|
33
35
|
gem 'wherewolf'
|
34
36
|
|
35
|
-
|
37
|
+
Then for every model that you want to by queryable, do this:
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
* !=
|
43
|
-
* <
|
44
|
-
* <=
|
45
|
-
* >
|
46
|
-
* >=
|
47
|
-
* Parenthesis
|
48
|
-
|
49
|
-
Need to implement:
|
50
|
-
|
51
|
-
* Aliases such for operators, such as 'and', 'or' etc
|
52
|
-
* Allow from_query to nested (ie Player.where('first_cap < 2000-01-01').from_query('active = true')
|
53
|
-
* More edge case testing
|
39
|
+
class Player < ActiveRecord::Base
|
40
|
+
has_query_parsing
|
41
|
+
end
|
42
|
+
|
43
|
+
This will add the "from_query" method, which you pass your query string in to.
|
54
44
|
|
55
45
|
== Example
|
56
46
|
|
47
|
+
For a real-life, running example, check out: http://wherewolf.herokuapp.com/
|
48
|
+
|
57
49
|
player = Player.from_query("(position = wing || position = lock) && first_cap < 1905-01-01").order('first_cap')
|
50
|
+
# Returns all players that play 'wing' or 'lock', and played before 1905-01-01
|
51
|
+
|
52
|
+
player = Player.from_query('name = "John Eales"')
|
53
|
+
# Returns all players names 'John Eales'
|
54
|
+
|
55
|
+
player = Player.from_query("first_cap >= 1905-01-01 && active = false")
|
56
|
+
# Returns all inactitve players that played after 1905-01-01.
|
57
|
+
|
58
|
+
player = Player.from_query("first_cap != null")
|
59
|
+
# Returns all players who have received their first cap (ie first_cap is NOT nil)
|
60
|
+
|
61
|
+
player = Player.from_query('name ~= "Peter%"')
|
62
|
+
# Returns all players who's name starts with Peter
|
63
|
+
|
64
|
+
As you can see, from_query returns an ARel object, so you chain other statements to it. Please note, though: at the moment from_query needs to be the first in the chain.
|
65
|
+
|
66
|
+
== Errors
|
67
|
+
|
68
|
+
At the moment, error handling is very primitive. Just capture
|
69
|
+
|
70
|
+
Wherewolf::ParseError
|
71
|
+
|
72
|
+
You can print out a simple error message like so
|
73
|
+
|
74
|
+
begin
|
75
|
+
Player.from_query('name ~= "Patrick%" || (position = "fail)')
|
76
|
+
rescue Wherewolf::ParseError => e
|
77
|
+
puts e.error_message
|
78
|
+
end
|
79
|
+
|
80
|
+
Will print out
|
81
|
+
|
82
|
+
Parsing error occured at character 28
|
83
|
+
|
84
|
+
You can get the character number by:
|
85
|
+
|
86
|
+
begin
|
87
|
+
Player.from_query('name ~= "Patrick%" || (position = "fail)')
|
88
|
+
rescue Wherewolf::ParseError => e
|
89
|
+
e.position # This value will be 28
|
90
|
+
end
|
91
|
+
|
92
|
+
== To Do
|
93
|
+
|
94
|
+
* Better error messages (Give a clue as to why parsing failed)
|
95
|
+
* Aliases such for operators, such as 'and', 'or' etc
|
96
|
+
* Allow single quotes around strings
|
97
|
+
* Allow from_query to nested (ie Player.where('first_cap < 2000-01-01').from_query('active = true')
|
98
|
+
* More edge case testing
|
99
|
+
* Abillity to filter columns that are searchable
|
100
|
+
* Ability to call named scopes
|
58
101
|
|
59
102
|
== Contributing to wherewolf
|
60
103
|
|
data/Rakefile
CHANGED
@@ -18,11 +18,11 @@ Jeweler::Tasks.new do |gem|
|
|
18
18
|
gem.name = "wherewolf"
|
19
19
|
gem.homepage = "http://github.com/madpilot/wherewolf"
|
20
20
|
gem.license = "MIT"
|
21
|
-
gem.summary = %Q{
|
22
|
-
gem.description = %Q{Wherewolf allows you to consume search terms as strings without worrying about database injections. It parses the query and converts it into
|
21
|
+
gem.summary = %Q{Makes filtering and searching to your REST API crazy easy.}
|
22
|
+
gem.description = %Q{Wherewolf allows you to consume search terms as strings without worrying about database injections. It parses the query and converts it into ARel. It's great for creating filterable REST APIs.}
|
23
23
|
gem.email = "myles@madpilot.com.au"
|
24
24
|
gem.authors = ["Myles Eftos"]
|
25
|
-
gem.version = "0.
|
25
|
+
gem.version = "0.2.0"
|
26
26
|
# dependencies defined in Gemfile
|
27
27
|
end
|
28
28
|
Jeweler::RubygemsDotOrgTasks.new
|
data/lib/wherewolf.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Wherewolf
|
2
|
+
class ParseError < Parslet::ParseFailed
|
3
|
+
attr_reader :parent
|
4
|
+
def initialize(parent)
|
5
|
+
@parent = parent
|
6
|
+
end
|
7
|
+
|
8
|
+
def position
|
9
|
+
parent.cause.source.pos
|
10
|
+
end
|
11
|
+
|
12
|
+
def error_message
|
13
|
+
"Parsing error occured at character #{position}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
error_message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/wherewolf/parser.rb
CHANGED
@@ -10,6 +10,7 @@ module Wherewolf
|
|
10
10
|
# Comparisons
|
11
11
|
rule(:eq) { str('=') }
|
12
12
|
rule(:not_eq) { str('!=') }
|
13
|
+
rule(:matches) { str('~=') }
|
13
14
|
rule(:lt) { str('<') }
|
14
15
|
rule(:lteq) { str('<=') }
|
15
16
|
rule(:gt) { str('>') }
|
@@ -33,16 +34,17 @@ module Wherewolf
|
|
33
34
|
end
|
34
35
|
rule(:literal) { match('[a-zA-Z0-9\-_]').repeat(1) }
|
35
36
|
rule(:identifier) { null | boolean | number | double_quote_string | literal.as(:string) }
|
36
|
-
|
37
|
+
|
37
38
|
# Grammar
|
38
39
|
rule(:compare_eq) { (literal.as(:left) >> space? >> eq >> space? >> identifier.as(:right)).as(:eq) }
|
39
40
|
rule(:compare_not_eq) { (literal.as(:left) >> space? >> not_eq >> space? >> identifier.as(:right)).as(:not_eq) }
|
41
|
+
rule(:compare_matches) { (literal.as(:left) >> space? >> matches >> space? >> identifier.as(:right)).as(:matches) }
|
40
42
|
rule(:compare_lt) { (literal.as(:left) >> space? >> lt >> space? >> identifier.as(:right)).as(:lt) }
|
41
43
|
rule(:compare_lteq) { (literal.as(:left) >> space? >> lteq >> space? >> identifier.as(:right)).as(:lteq) }
|
42
44
|
rule(:compare_gt) { (literal.as(:left) >> space? >> gt >> space? >> identifier.as(:right)).as(:gt) }
|
43
45
|
rule(:compare_gteq) { (literal.as(:left) >> space? >> gteq >> space? >> identifier.as(:right)).as(:gteq) }
|
44
46
|
|
45
|
-
rule(:compare) { compare_eq | compare_not_eq | compare_lteq | compare_lt | compare_gteq | compare_gt }
|
47
|
+
rule(:compare) { compare_eq | compare_not_eq | compare_matches | compare_lteq | compare_lt | compare_gteq | compare_gt }
|
46
48
|
|
47
49
|
rule(:primary) { left_parenthesis >> space? >> or_operation >> space? >> right_parenthesis | compare }
|
48
50
|
rule(:and_operation) { (primary.as(:left) >> space? >> and_operator >> space? >> and_operation.as(:right)).as(:and) | primary }
|
data/lib/wherewolf/processor.rb
CHANGED
@@ -8,9 +8,13 @@ module Wherewolf
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def parse(model, query)
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
begin
|
12
|
+
ast = Wherewolf::Parser.new.parse(query)
|
13
|
+
table = model.arel_table
|
14
|
+
model.where(process(ast, table))
|
15
|
+
rescue Parslet::ParseFailed => error
|
16
|
+
raise Wherewolf::ParseError, error
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
20
|
def process(ast, table)
|
@@ -35,6 +39,10 @@ protected
|
|
35
39
|
table[ast[:left].to_sym].not_eq(parse_value(ast[:right]))
|
36
40
|
end
|
37
41
|
|
42
|
+
def process_matches(ast, table)
|
43
|
+
table[ast[:left].to_sym].matches(parse_value(ast[:right]))
|
44
|
+
end
|
45
|
+
|
38
46
|
def process_lt(ast, table)
|
39
47
|
table[ast[:left].to_sym].lt(parse_value(ast[:right]))
|
40
48
|
end
|
data/test/parser_test.rb
CHANGED
@@ -76,6 +76,25 @@ class ParserTest < Test::Unit::TestCase
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
+
context "matches" do
|
80
|
+
should 'parse [op1]~=[op2]' do
|
81
|
+
result = @parser.parse('name~="Myles"')
|
82
|
+
assert_equal( { :matches => { :left => "name", :right => { :string => "Myles" } } }, result)
|
83
|
+
end
|
84
|
+
should 'parse [op1] ~=[op2]' do
|
85
|
+
result = @parser.parse('name ~="Myles"')
|
86
|
+
assert_equal( { :matches => { :left => "name", :right => { :string => "Myles" } } }, result)
|
87
|
+
end
|
88
|
+
should 'parse [op1]~= [op2]' do
|
89
|
+
result = @parser.parse('name~= "Myles"')
|
90
|
+
assert_equal( { :matches => { :left => "name", :right => { :string => "Myles" } } }, result)
|
91
|
+
end
|
92
|
+
should 'parse [op1] ~= [op2]' do
|
93
|
+
result = @parser.parse('name ~= "Myles"')
|
94
|
+
assert_equal( { :matches => { :left => "name", :right => { :string => "Myles" } } }, result)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
79
98
|
context "less than" do
|
80
99
|
should 'parse [op1]<[op2]' do
|
81
100
|
result = @parser.parse("size<12")
|
data/test/processor_test.rb
CHANGED
@@ -27,6 +27,40 @@ class ProcessorTest < Test::Unit::TestCase
|
|
27
27
|
end
|
28
28
|
|
29
29
|
context 'Parsing' do
|
30
|
+
context 'Error' do
|
31
|
+
should 'be raised is there is a parser error' do
|
32
|
+
assert_raise Wherewolf::ParseError do
|
33
|
+
Player.from_query('name ~= "Patrick%" || (position = "fail)')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
should 'allow retrieval of the error position' do
|
38
|
+
begin
|
39
|
+
Player.from_query('name ~= "Patrick%" || (position = "fail)')
|
40
|
+
rescue Wherewolf::ParseError => e
|
41
|
+
assert_equal 28, e.position
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
should 'show a nice debug error' do
|
47
|
+
begin
|
48
|
+
Player.from_query('name ~= "Patrick%" || (position = "fail)')
|
49
|
+
rescue Wherewolf::ParseError => e
|
50
|
+
assert_equal "Parsing error occured at character 28", e.error_message
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
should 'to_s should print out nice error' do
|
55
|
+
begin
|
56
|
+
Player.from_query('name ~= "Patrick%" || (position = "fail)')
|
57
|
+
rescue Wherewolf::ParseError => e
|
58
|
+
assert_equal "Parsing error occured at character 28", e.to_s
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
30
64
|
should 'construct simple boolean statements' do
|
31
65
|
player = Player.from_query('name = "Charlie Ellis"')
|
32
66
|
assert_equal 1, player.count
|
@@ -47,6 +81,12 @@ class ProcessorTest < Test::Unit::TestCase
|
|
47
81
|
assert_equal "Charlie Redwood", player[2].name
|
48
82
|
end
|
49
83
|
|
84
|
+
should 'handle matches' do
|
85
|
+
player = Player.from_query('name ~= "James%"')
|
86
|
+
assert_equal 1, player.count
|
87
|
+
assert_equal "James Slipper", player.first.name
|
88
|
+
end
|
89
|
+
|
50
90
|
should 'handle nulls' do
|
51
91
|
player = Player.from_query("first_cap = null")
|
52
92
|
assert_equal 1, player.count
|
data/wherewolf.gemspec
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "wherewolf"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Myles Eftos"]
|
12
12
|
s.date = "2012-10-10"
|
13
|
-
s.description = "Wherewolf allows you to consume search terms as strings without worrying about database injections. It parses the query and converts it into
|
13
|
+
s.description = "Wherewolf allows you to consume search terms as strings without worrying about database injections. It parses the query and converts it into ARel. It's great for creating filterable REST APIs."
|
14
14
|
s.email = "myles@madpilot.com.au"
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE.txt",
|
@@ -25,10 +25,12 @@ Gem::Specification.new do |s|
|
|
25
25
|
"README.rdoc",
|
26
26
|
"Rakefile",
|
27
27
|
"lib/wherewolf.rb",
|
28
|
+
"lib/wherewolf/parse_error.rb",
|
28
29
|
"lib/wherewolf/parser.rb",
|
29
30
|
"lib/wherewolf/processor.rb",
|
30
31
|
"lib/wherewolf/railtie.rb",
|
31
32
|
"test/helper.rb",
|
33
|
+
"test/parse_error_test.rb",
|
32
34
|
"test/parser_test.rb",
|
33
35
|
"test/processor_test.rb",
|
34
36
|
"test/railtie_test.rb",
|
@@ -38,7 +40,7 @@ Gem::Specification.new do |s|
|
|
38
40
|
s.licenses = ["MIT"]
|
39
41
|
s.require_paths = ["lib"]
|
40
42
|
s.rubygems_version = "1.8.15"
|
41
|
-
s.summary = "
|
43
|
+
s.summary = "Makes filtering and searching to your REST API crazy easy."
|
42
44
|
|
43
45
|
if s.respond_to? :specification_version then
|
44
46
|
s.specification_version = 3
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wherewolf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-10-10 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: arel
|
16
|
-
requirement: &
|
16
|
+
requirement: &70166778516180 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70166778516180
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: parslet
|
27
|
-
requirement: &
|
27
|
+
requirement: &70166778514340 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70166778514340
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: shoulda
|
38
|
-
requirement: &
|
38
|
+
requirement: &70166778512340 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70166778512340
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rdoc
|
49
|
-
requirement: &
|
49
|
+
requirement: &70166778511320 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70166778511320
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: bundler
|
60
|
-
requirement: &
|
60
|
+
requirement: &70166778510520 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70166778510520
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: jeweler
|
71
|
-
requirement: &
|
71
|
+
requirement: &70166778509620 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70166778509620
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: guard
|
82
|
-
requirement: &
|
82
|
+
requirement: &70166778525100 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70166778525100
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: guard-test
|
93
|
-
requirement: &
|
93
|
+
requirement: &70166778524220 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70166778524220
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: simplecov
|
104
|
-
requirement: &
|
104
|
+
requirement: &70166778522920 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70166778522920
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: sqlite3
|
115
|
-
requirement: &
|
115
|
+
requirement: &70166778521500 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *70166778521500
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: rails
|
126
|
-
requirement: &
|
126
|
+
requirement: &70166778520140 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ! '>='
|
@@ -131,10 +131,10 @@ dependencies:
|
|
131
131
|
version: '0'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *70166778520140
|
135
135
|
- !ruby/object:Gem::Dependency
|
136
136
|
name: wherewolf
|
137
|
-
requirement: &
|
137
|
+
requirement: &70166778519320 !ruby/object:Gem::Requirement
|
138
138
|
none: false
|
139
139
|
requirements:
|
140
140
|
- - ! '>='
|
@@ -142,10 +142,10 @@ dependencies:
|
|
142
142
|
version: '0'
|
143
143
|
type: :development
|
144
144
|
prerelease: false
|
145
|
-
version_requirements: *
|
145
|
+
version_requirements: *70166778519320
|
146
146
|
description: Wherewolf allows you to consume search terms as strings without worrying
|
147
|
-
about database injections. It parses the query and converts it into
|
148
|
-
for creating filterable REST APIs
|
147
|
+
about database injections. It parses the query and converts it into ARel. It's great
|
148
|
+
for creating filterable REST APIs.
|
149
149
|
email: myles@madpilot.com.au
|
150
150
|
executables: []
|
151
151
|
extensions: []
|
@@ -161,10 +161,12 @@ files:
|
|
161
161
|
- README.rdoc
|
162
162
|
- Rakefile
|
163
163
|
- lib/wherewolf.rb
|
164
|
+
- lib/wherewolf/parse_error.rb
|
164
165
|
- lib/wherewolf/parser.rb
|
165
166
|
- lib/wherewolf/processor.rb
|
166
167
|
- lib/wherewolf/railtie.rb
|
167
168
|
- test/helper.rb
|
169
|
+
- test/parse_error_test.rb
|
168
170
|
- test/parser_test.rb
|
169
171
|
- test/processor_test.rb
|
170
172
|
- test/railtie_test.rb
|
@@ -184,7 +186,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
184
186
|
version: '0'
|
185
187
|
segments:
|
186
188
|
- 0
|
187
|
-
hash:
|
189
|
+
hash: -122893438368244231
|
188
190
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
191
|
none: false
|
190
192
|
requirements:
|
@@ -196,5 +198,5 @@ rubyforge_project:
|
|
196
198
|
rubygems_version: 1.8.15
|
197
199
|
signing_key:
|
198
200
|
specification_version: 3
|
199
|
-
summary:
|
201
|
+
summary: Makes filtering and searching to your REST API crazy easy.
|
200
202
|
test_files: []
|