acts_as_explorable 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.travis.yml +23 -0
- data/Appraisals +12 -0
- data/Gemfile +15 -0
- data/Guardfile +5 -0
- data/MIT-LICENSE +20 -0
- data/README.md +52 -0
- data/Rakefile +22 -0
- data/acts_as_explorable.gemspec +28 -0
- data/gemfiles/activerecord_4.0.gemfile +19 -0
- data/gemfiles/activerecord_4.1.gemfile +19 -0
- data/gemfiles/activerecord_4.2.gemfile +20 -0
- data/lib/acts_as_explorable/configuration.rb +9 -0
- data/lib/acts_as_explorable/element/base.rb +8 -0
- data/lib/acts_as_explorable/element/dynamic_filter.rb +15 -0
- data/lib/acts_as_explorable/element/in.rb +18 -0
- data/lib/acts_as_explorable/element/sort.rb +20 -0
- data/lib/acts_as_explorable/element.rb +83 -0
- data/lib/acts_as_explorable/explorable.rb +76 -0
- data/lib/acts_as_explorable/ext/string.rb +24 -0
- data/lib/acts_as_explorable/parser.rb +61 -0
- data/lib/acts_as_explorable/query.rb +36 -0
- data/lib/acts_as_explorable/version.rb +3 -0
- data/lib/acts_as_explorable.rb +45 -0
- data/lib/tasks/acts_as_explorable_tasks.rake +4 -0
- data/spec/factories/players.rb +57 -0
- data/spec/lib/acts_as_explorable/element/dynamic_filter_spec.rb +19 -0
- data/spec/lib/acts_as_explorable/element/in.rb +12 -0
- data/spec/lib/acts_as_explorable/element_spec.rb +16 -0
- data/spec/lib/acts_as_explorable/explorable_spec.rb +28 -0
- data/spec/lib/acts_as_explorable/parser_spec.rb +35 -0
- data/spec/lib/acts_as_explorable/query_spec.rb +51 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/database.rb +64 -0
- data/spec/support/database_cleaner.rb +21 -0
- metadata +185 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: cf09cef7bef8fb847eceda7eb6ab0ffe5a3d9d72
|
|
4
|
+
data.tar.gz: a7b61b25db90271f6787c8e3140ca097500f5445
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 3856e51cda905223c8d4c3d35456d7db75d69573bf810c0d61f911f0432e3069f24ea53c1bb749690d8ad58e4750755d63a46f0c7592fabf258b5f650698d16b
|
|
7
|
+
data.tar.gz: 8f2fec4eb042b5a9f48aa665cc37c51b3a5e7251c9e9f485de2b415db2bc9c8df0a450dd97c74efaacd03011118bbfdea5e19c6f3d9814cef64d50077e6d0f6f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
language: ruby
|
|
2
|
+
rvm:
|
|
3
|
+
- 2.1
|
|
4
|
+
- 2.2
|
|
5
|
+
- 2.0.0
|
|
6
|
+
- rbx-2
|
|
7
|
+
|
|
8
|
+
gemfile:
|
|
9
|
+
- gemfiles/activerecord_4.0.gemfile
|
|
10
|
+
- gemfiles/activerecord_4.1.gemfile
|
|
11
|
+
- gemfiles/activerecord_4.2.gemfile
|
|
12
|
+
|
|
13
|
+
sudo: false
|
|
14
|
+
|
|
15
|
+
bundler_args: '--without local_development yard --jobs 3 --retry 3'
|
|
16
|
+
|
|
17
|
+
script: bundle exec rake
|
|
18
|
+
|
|
19
|
+
matrix:
|
|
20
|
+
fast_finish: true
|
|
21
|
+
allow_failures:
|
|
22
|
+
- gemfile: gemfiles/activerecord_edge.gemfile
|
|
23
|
+
- rvm: rbx-2
|
data/Appraisals
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
appraise "activerecord-4.0" do
|
|
2
|
+
gem "activerecord", github: "rails/rails" , branch: '4-0-stable'
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
appraise "activerecord-4.1" do
|
|
6
|
+
gem "activerecord", github: "rails/rails" , branch: '4-1-stable'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
appraise "activerecord-4.2" do
|
|
10
|
+
gem "railties", github: "rails/rails" , branch: '4-2-stable'
|
|
11
|
+
gem "activerecord", github: "rails/rails" , branch: '4-2-stable'
|
|
12
|
+
end
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2015 Mathias Schneider
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Acts As Explorable
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/hiasinho/acts_as_explorable) [](https://codeclimate.com/github/hiasinho/acts_as_explorable) [](http://inch-ci.org/github/hiasinho/acts_as_explorable)
|
|
4
|
+
|
|
5
|
+
Acts As Explorable is a Ruby Gem specifically written for ActiveRecord models.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
### Supported Ruby and Rails versions
|
|
10
|
+
|
|
11
|
+
* Ruby 2.0.0, 2.1.0
|
|
12
|
+
* Rails 4.0, 4.1, 4.2+
|
|
13
|
+
|
|
14
|
+
### Install
|
|
15
|
+
|
|
16
|
+
THIS GEM IS NOT RELEASED YET. SO, THIS WON'T WORK!
|
|
17
|
+
|
|
18
|
+
Just add the following to your Gemfile.
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
gem 'acts_as_explorable', '~> 0.0.1'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
And follow that up with a ``bundle install``.
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
TODO
|
|
29
|
+
|
|
30
|
+
## Testing
|
|
31
|
+
|
|
32
|
+
All tests follow the RSpec format and are located in the spec directory.
|
|
33
|
+
They can be run with:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
rake spec
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## License
|
|
40
|
+
|
|
41
|
+
Acts as explorable is released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
|
42
|
+
|
|
43
|
+
## TODO
|
|
44
|
+
|
|
45
|
+
### v0.1
|
|
46
|
+
- Fill this README file
|
|
47
|
+
- Release v0.0.1 to rubygems
|
|
48
|
+
|
|
49
|
+
###v0.x
|
|
50
|
+
- Add tests for postgres and mysql
|
|
51
|
+
- Query string validation helper for use in forms
|
|
52
|
+
- Use methods in addition to fields
|
data/Rakefile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
|
|
4
|
+
desc 'Default: run specs.'
|
|
5
|
+
task default: :spec
|
|
6
|
+
|
|
7
|
+
require 'rspec/core/rake_task'
|
|
8
|
+
RSpec::Core::RakeTask.new do |t|
|
|
9
|
+
t.pattern = 'spec/**/*_spec.rb'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
require 'yard'
|
|
13
|
+
YARD::Rake::YardocTask.new do |t|
|
|
14
|
+
t.options << '--output-dir' << './doc'
|
|
15
|
+
t.options << '--no-private'
|
|
16
|
+
t.options << '--protected'
|
|
17
|
+
t.options << '--readme' << 'README.md'
|
|
18
|
+
t.options << '--hide-tag' << 'return'
|
|
19
|
+
t.options << '--hide-tag' << 'param'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Bundler::GemHelper.install_tasks
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
|
2
|
+
require 'acts_as_explorable/version'
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = 'acts_as_explorable'
|
|
6
|
+
s.version = ActsAsExplorable::VERSION
|
|
7
|
+
s.authors = ['Mathias Schneider']
|
|
8
|
+
s.email = ['mathias@hiasinho.com']
|
|
9
|
+
s.homepage = 'https://github.com/hiasinho/acts_as_explorable'
|
|
10
|
+
s.summary = 'Adds GitHub-like search function to your models'
|
|
11
|
+
s.description = 'Adds GitHub-like search function to your models'
|
|
12
|
+
s.license = 'MIT'
|
|
13
|
+
|
|
14
|
+
s.files = `git ls-files`.split("\n")
|
|
15
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
|
16
|
+
s.require_paths = ['lib']
|
|
17
|
+
s.required_ruby_version = '>= 2.0.0'
|
|
18
|
+
|
|
19
|
+
s.add_runtime_dependency 'activerecord', ['>= 4.0', '< 5']
|
|
20
|
+
|
|
21
|
+
s.add_development_dependency 'sqlite3'
|
|
22
|
+
|
|
23
|
+
s.add_development_dependency 'rspec-rails'
|
|
24
|
+
s.add_development_dependency 'rspec-its'
|
|
25
|
+
s.add_development_dependency 'rspec'
|
|
26
|
+
s.add_development_dependency 'factory_girl_rails', '~> 4.0'
|
|
27
|
+
s.add_development_dependency 'database_cleaner'
|
|
28
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "activerecord", :github => "rails/rails", :branch => "4-0-stable"
|
|
6
|
+
|
|
7
|
+
group :doc do
|
|
8
|
+
gem "yard"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
group :local_development do
|
|
12
|
+
gem "guard"
|
|
13
|
+
gem "guard-rspec"
|
|
14
|
+
gem "appraisal"
|
|
15
|
+
gem "rake"
|
|
16
|
+
gem "byebug", :platform => :mri_21
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
gemspec :path => "../"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "activerecord", :github => "rails/rails", :branch => "4-1-stable"
|
|
6
|
+
|
|
7
|
+
group :doc do
|
|
8
|
+
gem "yard"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
group :local_development do
|
|
12
|
+
gem "guard"
|
|
13
|
+
gem "guard-rspec"
|
|
14
|
+
gem "appraisal"
|
|
15
|
+
gem "rake"
|
|
16
|
+
gem "byebug", :platform => :mri_21
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
gemspec :path => "../"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# This file was generated by Appraisal
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
gem "railties", :github => "rails/rails", :branch => "4-2-stable"
|
|
6
|
+
gem "activerecord", :github => "rails/rails", :branch => "4-2-stable"
|
|
7
|
+
|
|
8
|
+
group :doc do
|
|
9
|
+
gem "yard"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
group :local_development do
|
|
13
|
+
gem "guard"
|
|
14
|
+
gem "guard-rspec"
|
|
15
|
+
gem "appraisal"
|
|
16
|
+
gem "rake"
|
|
17
|
+
gem "byebug", :platform => :mri_21
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
gemspec :path => "../"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module ActsAsExplorable::Element
|
|
2
|
+
#
|
|
3
|
+
# Generates a +where+ clause to look up the searched string in the given columns
|
|
4
|
+
#
|
|
5
|
+
class DynamicFilter < Base
|
|
6
|
+
def after_init
|
|
7
|
+
@query_type = :where
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def render
|
|
11
|
+
@query_parts << table[type].lower.in(@parameters)
|
|
12
|
+
@full_query = @query_parts.first
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module ActsAsExplorable::Element
|
|
2
|
+
#
|
|
3
|
+
# Generates a +where+ clause to look up the searched string in the given columns
|
|
4
|
+
#
|
|
5
|
+
class In < Base
|
|
6
|
+
def after_init
|
|
7
|
+
@query_type = :where
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def render
|
|
11
|
+
@parameters.each do |f|
|
|
12
|
+
@query_parts <<
|
|
13
|
+
table[f.to_sym].matches_any(@query_string.map { |q| "%#{q}%" })
|
|
14
|
+
end
|
|
15
|
+
@full_query = @query_parts.inject(:or)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module ActsAsExplorable::Element
|
|
2
|
+
#
|
|
3
|
+
# Generates an +order+ query part to sort by the given columns
|
|
4
|
+
#
|
|
5
|
+
class Sort < Base
|
|
6
|
+
def after_init
|
|
7
|
+
@query_type = :reorder
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def render
|
|
11
|
+
@full_query = @parameters.map do |f|
|
|
12
|
+
if f =~ /(-asc|-desc)/
|
|
13
|
+
{ f.split('-').first.to_sym => f.split('-').last.to_sym }
|
|
14
|
+
else
|
|
15
|
+
{ f.to_sym => :desc }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'acts_as_explorable/element/base'
|
|
2
|
+
require 'acts_as_explorable/element/in'
|
|
3
|
+
require 'acts_as_explorable/element/sort'
|
|
4
|
+
require 'acts_as_explorable/element/dynamic_filter'
|
|
5
|
+
|
|
6
|
+
module ActsAsExplorable
|
|
7
|
+
module Element
|
|
8
|
+
attr_accessor :query_type, :model, :parameters, :query_string, :query_parts,
|
|
9
|
+
:full_query
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# This method acts as a factory to build a concrete element
|
|
13
|
+
#
|
|
14
|
+
# @example
|
|
15
|
+
# ActsAsExplorable::Element.build(:in, 'Zlatan in:first_name', Player)
|
|
16
|
+
#
|
|
17
|
+
# @param type [Symbol] The element type to be build
|
|
18
|
+
# @param query [String] The query string
|
|
19
|
+
# @param model [ActiveRecord::Base] Anactive record model
|
|
20
|
+
#
|
|
21
|
+
# @return [ActsAsExplorable::Element] A concrete element type
|
|
22
|
+
def self.build(type, query, model)
|
|
23
|
+
klass = Module.nesting.last.const_get('Element').const_get(type.to_s.camelize)
|
|
24
|
+
instance = klass.new(query, model, type)
|
|
25
|
+
rescue NameError
|
|
26
|
+
DynamicFilter.new(query, model, type)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def initialize(query, model, element_type = nil)
|
|
30
|
+
query = query.to_acts_as_explorable(ActsAsExplorable.filters.keys)
|
|
31
|
+
|
|
32
|
+
@type = element_type if element_type
|
|
33
|
+
@model = model
|
|
34
|
+
@query_string = query[:values]
|
|
35
|
+
@query_parts = []
|
|
36
|
+
filter_parameters(query[:params])
|
|
37
|
+
after_init
|
|
38
|
+
|
|
39
|
+
render if @parameters.present?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def after_init; end
|
|
43
|
+
|
|
44
|
+
def execute(query_object)
|
|
45
|
+
query_object.send(@query_type, @full_query)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
protected
|
|
49
|
+
|
|
50
|
+
def filter_parameters(params)
|
|
51
|
+
return unless params[type]
|
|
52
|
+
@parameters = params[type].select do |f|
|
|
53
|
+
filters.find do |e|
|
|
54
|
+
/#{e.to_sym}(?:-\w+)?/ =~ f
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
#
|
|
60
|
+
# Returns the Arel table for the current model
|
|
61
|
+
#
|
|
62
|
+
# @return [Arel::Table] Arel table for the current model
|
|
63
|
+
def table
|
|
64
|
+
@model.arel_table
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def render
|
|
68
|
+
fail "`#render` needs to be implemented for #{self.class.name}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def type
|
|
72
|
+
@type.to_sym || self.class.name.demodulize.underscore.to_sym
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
# Returns the customized filters
|
|
77
|
+
#
|
|
78
|
+
# @return [Hash] The customized filters
|
|
79
|
+
def filters
|
|
80
|
+
ActsAsExplorable.filters[type]
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module ActsAsExplorable
|
|
2
|
+
module Explorable
|
|
3
|
+
def self.extended(base)
|
|
4
|
+
base.class_eval do
|
|
5
|
+
def self.explorable?
|
|
6
|
+
false
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Configure ActsAsExplorable's behavior in a model.
|
|
12
|
+
#
|
|
13
|
+
# The plugin can be customized using parameters or through a `block`.
|
|
14
|
+
#
|
|
15
|
+
# class Player < ActiveRecord::Base
|
|
16
|
+
# extend ActsAsExplorable
|
|
17
|
+
# explorable in: [:first_name, :last_name, :position, :city, :club],
|
|
18
|
+
# sort: [:first_name, :last_name, :position, :city, :club, :created_at],
|
|
19
|
+
# position: ['GK', 'MF', 'FW']
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# Using a block (TODO: This will be available in future versions):
|
|
23
|
+
#
|
|
24
|
+
# class Player < ActiveRecord::Base
|
|
25
|
+
# extend ActsAsExplorable
|
|
26
|
+
# explorable do |config|
|
|
27
|
+
# config.filters = {
|
|
28
|
+
# in: [:first_name, :last_name, :position, :city, :club],
|
|
29
|
+
# sort: [:first_name, :last_name, :position, :city, :club, :created_at],
|
|
30
|
+
# position: ['GK', 'MF', 'FW']
|
|
31
|
+
# }
|
|
32
|
+
# end
|
|
33
|
+
# end
|
|
34
|
+
#
|
|
35
|
+
# @yield Provides access to the model class's config, which
|
|
36
|
+
# allows to customize types and filters
|
|
37
|
+
#
|
|
38
|
+
# @yieldparam config The model class's {ActsAsExplorable::Configuration config}.
|
|
39
|
+
def explorable(filters = {}, &_block)
|
|
40
|
+
class_eval do
|
|
41
|
+
def self.explorable?
|
|
42
|
+
true
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
if block_given?
|
|
47
|
+
ActsAsExplorable.setup { |config| yield config }
|
|
48
|
+
else
|
|
49
|
+
explorable_set_filters filters
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
protected
|
|
54
|
+
|
|
55
|
+
# Configure ActsAsExplorable's permitted filters per type in a model.
|
|
56
|
+
#
|
|
57
|
+
# class Person < ActiveRecord::Base
|
|
58
|
+
# extend ActsAsExplorable
|
|
59
|
+
# explorable_filters in: [:first_name, :last_name, :city],
|
|
60
|
+
# sort: [:first_name, :last_name, :city, :created_at]
|
|
61
|
+
# end
|
|
62
|
+
#
|
|
63
|
+
# @param [Hash] filters Filters for types
|
|
64
|
+
# @return [Array] Permitted filters
|
|
65
|
+
#
|
|
66
|
+
def explorable_set_filters(filters = {})
|
|
67
|
+
ActsAsExplorable.filters = filters if filters.present?
|
|
68
|
+
|
|
69
|
+
ActsAsExplorable.filters.each_pair do |f, _a|
|
|
70
|
+
ActsAsExplorable.filters[f].map!(&:downcase)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
ActsAsExplorable.filters
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#
|
|
2
|
+
# A String extension for ActsAsExplorable
|
|
3
|
+
#
|
|
4
|
+
class String
|
|
5
|
+
# Converts the String into a Hash for ActsAsExplorable.
|
|
6
|
+
#
|
|
7
|
+
# == Returns:
|
|
8
|
+
# A Hash providing 2 keys:
|
|
9
|
+
# - <tt>:values</tt> holds the search text values
|
|
10
|
+
# - <tt>:params</tt> holds parameters (fields) to search in
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# query = "Foo Bar in:name,body sort:created_at-asc"
|
|
14
|
+
# query.to_acts_as_explorable
|
|
15
|
+
# # => {:values=>["Foo", "Bar"], :params=>{:in=>["name", "body"], :sort=>["created_at-asc"]}}
|
|
16
|
+
#
|
|
17
|
+
# @param keys [Array<String, Symbol>, nil] Array of accepted keys
|
|
18
|
+
#
|
|
19
|
+
# @return [Hash] Converted query
|
|
20
|
+
def to_acts_as_explorable(*keys)
|
|
21
|
+
return nil if self.blank?
|
|
22
|
+
ActsAsExplorable::Parser.transform(self, *keys)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module ActsAsExplorable
|
|
2
|
+
##
|
|
3
|
+
# Transforms query strings to a Hash that can be used by ActsAsExplorable.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# ActsAsExplorable::Parser.transform('Zlatan in:first_name')
|
|
7
|
+
# => { values: ["Zlatan"], params: { in: ["first_name"] } }
|
|
8
|
+
class Parser
|
|
9
|
+
attr_reader :values, :params, :props
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# Returns a transformed query Hash using the given query string
|
|
13
|
+
# @param query_string [String] A query string
|
|
14
|
+
# @param keys [Array] An Array of transformation rules
|
|
15
|
+
#
|
|
16
|
+
# @return [Hash] Transformed query
|
|
17
|
+
def self.transform(query_string, *keys)
|
|
18
|
+
instance = new(query_string)
|
|
19
|
+
instance.parse(*keys)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def initialize(query_string)
|
|
23
|
+
@query_string = query_string
|
|
24
|
+
split_query_string
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
#
|
|
28
|
+
# Parses the query string
|
|
29
|
+
# @param keys [Hash] An Array of transformation rules
|
|
30
|
+
#
|
|
31
|
+
# @return [Hash] Transformed query
|
|
32
|
+
def parse(*keys)
|
|
33
|
+
split_query_string
|
|
34
|
+
|
|
35
|
+
@props.each do |p|
|
|
36
|
+
key, params = p.split(':').first.to_sym, p.split(':').last.split(',')
|
|
37
|
+
next if !keys.flatten.include?(key) && !keys.empty?
|
|
38
|
+
@params[key] ||= []
|
|
39
|
+
@params[key] = @params[key] | params.map(&:downcase)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
{ values: @values, params: @params }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def split_query_string
|
|
48
|
+
@values = []
|
|
49
|
+
@params = {}
|
|
50
|
+
@props = []
|
|
51
|
+
|
|
52
|
+
@query_string.split(/\s+/).each do |q|
|
|
53
|
+
if q =~ /\w+:[\w,-]+/
|
|
54
|
+
@props << q
|
|
55
|
+
else
|
|
56
|
+
@values << q
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module ActsAsExplorable
|
|
2
|
+
#
|
|
3
|
+
# Adds the search scope to a model
|
|
4
|
+
#
|
|
5
|
+
module Query
|
|
6
|
+
#
|
|
7
|
+
# Initiates a search with the given query string and returns an
|
|
8
|
+
# <tt>ActiveRecord::Relation</tt> scope object.
|
|
9
|
+
#
|
|
10
|
+
# The query string's *syntax* is described in {file:docs/yard/README.md#syntax the Readme File}
|
|
11
|
+
#
|
|
12
|
+
# The search method can be used just like a scope.
|
|
13
|
+
#
|
|
14
|
+
# Foo.search("Foo Bar in:name,body sort:created_at-asc").to_sql
|
|
15
|
+
# # => "SELECT foo.* FROM foo WHERE (foo.body ILIKE '%Foo%' OR foo.body ILIKE '%Bar%') ORDER BY foo.created_at ASC"
|
|
16
|
+
#
|
|
17
|
+
# It is also possible to put it in a scope chain like this:
|
|
18
|
+
#
|
|
19
|
+
# Foo.published.search("Foo Bar in:name,body sort:created_at-asc")
|
|
20
|
+
#
|
|
21
|
+
# @param [String] query_string A query string
|
|
22
|
+
# @return [ActiveRecord::Relation] Returns an <tt>ActiveRecord::Relation</tt> scope object
|
|
23
|
+
#
|
|
24
|
+
def search(query_string)
|
|
25
|
+
parts = ActsAsExplorable.filters.keys.map { |t| Element.build(t, query_string, self) }
|
|
26
|
+
|
|
27
|
+
result = all
|
|
28
|
+
|
|
29
|
+
parts.compact.each do |part|
|
|
30
|
+
result = part.execute(result)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
result
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
require 'active_support/inflector'
|
|
3
|
+
require 'acts_as_explorable/version'
|
|
4
|
+
require 'acts_as_explorable/configuration'
|
|
5
|
+
require 'acts_as_explorable/parser'
|
|
6
|
+
require 'acts_as_explorable/ext/string'
|
|
7
|
+
require 'acts_as_explorable/element'
|
|
8
|
+
require 'acts_as_explorable/explorable'
|
|
9
|
+
require 'acts_as_explorable/query'
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# ActsAsExplorable Plugin
|
|
13
|
+
#
|
|
14
|
+
# @author hiasinho
|
|
15
|
+
#
|
|
16
|
+
module ActsAsExplorable
|
|
17
|
+
def self.extended(base)
|
|
18
|
+
base.extend Query
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.method_missing(method_name, *args, &block)
|
|
22
|
+
if @configuration.respond_to?(method_name)
|
|
23
|
+
@configuration.send(method_name, *args, &block)
|
|
24
|
+
else
|
|
25
|
+
super
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.respond_to?(method_name, _include_private = false)
|
|
30
|
+
@configuration.respond_to? method_name
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
def self.setup
|
|
36
|
+
@configuration ||= Configuration.new
|
|
37
|
+
yield @configuration if block_given?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
setup
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
ActiveSupport.on_load(:active_record) do
|
|
44
|
+
extend ActsAsExplorable::Explorable
|
|
45
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
FactoryGirl.define do
|
|
2
|
+
factory :player, aliases: [:zlatan, :god_of_football] do
|
|
3
|
+
first_name 'Zlatan'
|
|
4
|
+
last_name 'Ibrahimovic'
|
|
5
|
+
position 'FW'
|
|
6
|
+
city 'Paris'
|
|
7
|
+
club 'PSG'
|
|
8
|
+
|
|
9
|
+
factory :manuel, aliases: [:goalkeeper] do
|
|
10
|
+
first_name 'Manuel'
|
|
11
|
+
last_name 'Neuer'
|
|
12
|
+
position 'GK'
|
|
13
|
+
city 'München'
|
|
14
|
+
club 'FC Bayern München'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
factory :bastian, aliases: [:schweini] do
|
|
18
|
+
first_name 'Bastian'
|
|
19
|
+
last_name 'Schweinsteiger'
|
|
20
|
+
position 'MF'
|
|
21
|
+
city 'München'
|
|
22
|
+
club 'FC Bayern München'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
factory :sascha do
|
|
26
|
+
first_name 'Sascha'
|
|
27
|
+
last_name 'Mölders'
|
|
28
|
+
position 'FW'
|
|
29
|
+
city 'Augsburg'
|
|
30
|
+
club 'FC Augsburg'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
factory :christiano, aliases: [:forward] do
|
|
34
|
+
first_name 'Christiano'
|
|
35
|
+
last_name 'Ronaldo'
|
|
36
|
+
position 'FW'
|
|
37
|
+
city 'Madrid'
|
|
38
|
+
club 'Real Madrid'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
factory :toni do
|
|
42
|
+
first_name 'Toni'
|
|
43
|
+
last_name 'Kroos'
|
|
44
|
+
position 'MF'
|
|
45
|
+
city 'Madrid'
|
|
46
|
+
club 'Real Madrid'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
factory :fernando do
|
|
50
|
+
first_name 'Fernando'
|
|
51
|
+
last_name 'Torres'
|
|
52
|
+
position 'FW'
|
|
53
|
+
city 'Madrid'
|
|
54
|
+
club 'Athletico Madrid'
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActsAsExplorable::Element::DynamicFilter do
|
|
4
|
+
|
|
5
|
+
subject { ActsAsExplorable::Element::DynamicFilter }
|
|
6
|
+
let (:element) { ActsAsExplorable::Element }
|
|
7
|
+
|
|
8
|
+
it 'should return a dynamic filter element' do
|
|
9
|
+
expect(element.build(:position, 'position:gk,mf,fw', Player)).to be_instance_of(subject)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'should filter by position' do
|
|
13
|
+
create(:goalkeeper)
|
|
14
|
+
create(:forward)
|
|
15
|
+
|
|
16
|
+
expect(Player.search('position:gk').count).to eq(1)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActsAsExplorable::Element::In do
|
|
4
|
+
|
|
5
|
+
subject { ActsAsExplorable::Element::In }
|
|
6
|
+
let (:element) { ActsAsExplorable::Element }
|
|
7
|
+
|
|
8
|
+
it 'should return a dynamic filter element' do
|
|
9
|
+
expect(element.build(:in, 'test in:first_name', Player)).to be_instance_of(subject)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActsAsExplorable::Element do
|
|
4
|
+
|
|
5
|
+
subject { ActsAsExplorable::Element }
|
|
6
|
+
|
|
7
|
+
describe '.build' do
|
|
8
|
+
it 'should be callable' do
|
|
9
|
+
expect(subject).to respond_to(:build)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'should create an element' do
|
|
13
|
+
expect(ActsAsExplorable::Element.build(:position, 'position:gk', Player)).to be_instance_of(ActsAsExplorable::Element::DynamicFilter)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
def create_player(klass = Player, factory: :player)
|
|
4
|
+
klass.create(attributes_for(factory))
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
describe ActsAsExplorable::Explorable do
|
|
8
|
+
|
|
9
|
+
let(:zlatan) { create(:zlatan) }
|
|
10
|
+
let(:manuel) { create(:manuel) }
|
|
11
|
+
let(:bastian) { create(:bastian) }
|
|
12
|
+
let(:christiano) { create(:christiano) }
|
|
13
|
+
let(:toni) { create(:toni) }
|
|
14
|
+
let(:fernando) { create(:fernando) }
|
|
15
|
+
|
|
16
|
+
it 'should not be explorable' do
|
|
17
|
+
expect(NotExplorable).not_to be_explorable
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'should be explorable' do
|
|
21
|
+
expect(Explorable).to be_explorable
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'should be customizable through a block' do
|
|
25
|
+
skip 'TODO: This will be available in future versions'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActsAsExplorable::Parser do
|
|
4
|
+
|
|
5
|
+
subject { ActsAsExplorable::Parser }
|
|
6
|
+
|
|
7
|
+
describe '#new' do
|
|
8
|
+
it 'should be called with a query string' do
|
|
9
|
+
expect { subject.new }.to raise_error
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '.transform' do
|
|
14
|
+
it 'should respond with a hash' do
|
|
15
|
+
expect(subject.transform('Zlatan in:first_name')).to be_a(Hash)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'should have a result with :values and :params keys' do
|
|
19
|
+
expect(subject.transform('Zlatan in:first_name'))
|
|
20
|
+
.to have_key(:values)
|
|
21
|
+
.and have_key(:params)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'should not have a result with a key :props' do
|
|
25
|
+
expect(subject.transform('Zlatan in:first_name'))
|
|
26
|
+
.not_to have_key(:props)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'should transform the string to a hash' do
|
|
30
|
+
expect(subject.transform('Zlatan in:first_name'))
|
|
31
|
+
.to eq(values: ['Zlatan'], params: { in: ['first_name'] })
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ActsAsExplorable::Query do
|
|
4
|
+
|
|
5
|
+
let(:zlatan) { create(:zlatan) }
|
|
6
|
+
let(:manuel) { create(:manuel) }
|
|
7
|
+
let(:bastian) { create(:bastian) }
|
|
8
|
+
let(:christiano) { create(:christiano) }
|
|
9
|
+
let(:toni) { create(:toni) }
|
|
10
|
+
let(:fernando) { create(:fernando) }
|
|
11
|
+
|
|
12
|
+
context 'in:' do
|
|
13
|
+
it '`first_name` should find by first name' do
|
|
14
|
+
[zlatan, christiano]
|
|
15
|
+
expect(Player.search('Zlatan in:first_name').count).to eq(1)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it '`club` should find by club' do
|
|
19
|
+
[zlatan, manuel, bastian]
|
|
20
|
+
expect(Player.search('Bayern in:club').count).to eq(2)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it '`city` should find by city' do
|
|
24
|
+
[zlatan, bastian, christiano, toni, fernando]
|
|
25
|
+
expect(Player.search('Madrid in:city').count).to eq(3)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'sort:' do
|
|
30
|
+
before(:each) do
|
|
31
|
+
[christiano, zlatan, bastian]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it '`first_name` should order descending by first name' do
|
|
35
|
+
expect(Player.search('sort:first_name').first).to eq(zlatan)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it '`first_name-desc` should order descending by first name' do
|
|
39
|
+
expect(Player.search('sort:first_name-desc').first).to eq(zlatan)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it '`first_name-asc` should order ascending by first name' do
|
|
43
|
+
expect(Player.search('sort:first_name-asc').last).to eq(zlatan)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it '`position-desc,first_name-asc` should order by position then by first name' do
|
|
47
|
+
expect(Player.search('sort:position-desc,first_name-asc').first).to eq(bastian)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'byebug'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
end
|
|
5
|
+
$LOAD_PATH << '.' unless $LOAD_PATH.include?('.')
|
|
6
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
|
7
|
+
require 'logger'
|
|
8
|
+
|
|
9
|
+
require File.expand_path('../../lib/acts_as_explorable', __FILE__)
|
|
10
|
+
I18n.enforce_available_locales = true
|
|
11
|
+
require 'rails'
|
|
12
|
+
require 'rspec/its'
|
|
13
|
+
require 'sqlite3'
|
|
14
|
+
require 'factory_girl'
|
|
15
|
+
require 'database_cleaner'
|
|
16
|
+
|
|
17
|
+
Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
|
|
18
|
+
|
|
19
|
+
RSpec.configure do |config|
|
|
20
|
+
config.include FactoryGirl::Syntax::Methods
|
|
21
|
+
config.raise_errors_for_deprecations!
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
FactoryGirl.find_definitions
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
ActiveRecord::Migration.verbose = false
|
|
2
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
|
3
|
+
ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), '../debug.log'))
|
|
4
|
+
ActiveRecord::Base.logger.level = ENV['TRAVIS'] ? ::Logger::ERROR : ::Logger::DEBUG
|
|
5
|
+
|
|
6
|
+
ActiveRecord::Schema.define(version: 1) do
|
|
7
|
+
create_table :players do |t|
|
|
8
|
+
t.string :first_name
|
|
9
|
+
t.string :last_name
|
|
10
|
+
t.string :position, limit: 2
|
|
11
|
+
t.string :city
|
|
12
|
+
t.string :club
|
|
13
|
+
|
|
14
|
+
t.timestamps null: false
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class ActsAsExplorable::TestModelBase < ActiveRecord::Base
|
|
19
|
+
self.table_name = :players
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class Player < ActsAsExplorable::TestModelBase
|
|
23
|
+
extend ActsAsExplorable
|
|
24
|
+
explorable in: [:first_name, :last_name, :position, :city, :club],
|
|
25
|
+
sort: [:first_name, :last_name, :position, :city, :club, :created_at],
|
|
26
|
+
position: %w(GK MF FW)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class ArgumentsPlayer < ActsAsExplorable::TestModelBase
|
|
30
|
+
extend ActsAsExplorable
|
|
31
|
+
explorable in: [:first_name, :last_name, :position, :city, :club],
|
|
32
|
+
sort: [:first_name, :last_name, :position, :city, :club, :created_at],
|
|
33
|
+
position: %w(GK MF FW)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class BlockPlayer < ActsAsExplorable::TestModelBase
|
|
37
|
+
extend ActsAsExplorable
|
|
38
|
+
explorable do |config|
|
|
39
|
+
config.filters = {
|
|
40
|
+
in: [:first_name, :last_name, :position, :city, :club],
|
|
41
|
+
sort: [:first_name, :last_name, :position, :city, :club, :created_at],
|
|
42
|
+
position: %w(GK MF FW)
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class BlockPlayer < ActsAsExplorable::TestModelBase
|
|
48
|
+
extend ActsAsExplorable
|
|
49
|
+
explorable in: [:first_name, :last_name, :position, :city, :club],
|
|
50
|
+
sort: [:first_name, :last_name, :position, :city, :club, :created_at],
|
|
51
|
+
position: %w(GK MF FW)
|
|
52
|
+
|
|
53
|
+
explorable do |_config|
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
class Explorable < ActsAsExplorable::TestModelBase
|
|
59
|
+
extend ActsAsExplorable
|
|
60
|
+
explorable
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class NotExplorable < ActsAsExplorable::TestModelBase
|
|
64
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
RSpec.configure do |config|
|
|
2
|
+
|
|
3
|
+
config.before(:suite) do
|
|
4
|
+
DatabaseCleaner.clean_with(:truncation)
|
|
5
|
+
DatabaseCleaner.strategy = :transaction
|
|
6
|
+
DatabaseCleaner.clean
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
config.after(:suite) do
|
|
10
|
+
DatabaseCleaner.clean
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
config.before(:each) do
|
|
14
|
+
DatabaseCleaner.start
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
config.after(:each) do
|
|
18
|
+
DatabaseCleaner.clean
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: acts_as_explorable
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Mathias Schneider
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-01-17 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: activerecord
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '4.0'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '5'
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '4.0'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '5'
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: sqlite3
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
type: :development
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: rspec-rails
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
- !ruby/object:Gem::Dependency
|
|
62
|
+
name: rspec-its
|
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
type: :development
|
|
69
|
+
prerelease: false
|
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
- !ruby/object:Gem::Dependency
|
|
76
|
+
name: rspec
|
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
type: :development
|
|
83
|
+
prerelease: false
|
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
- !ruby/object:Gem::Dependency
|
|
90
|
+
name: factory_girl_rails
|
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '4.0'
|
|
96
|
+
type: :development
|
|
97
|
+
prerelease: false
|
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '4.0'
|
|
103
|
+
- !ruby/object:Gem::Dependency
|
|
104
|
+
name: database_cleaner
|
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
type: :development
|
|
111
|
+
prerelease: false
|
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0'
|
|
117
|
+
description: Adds GitHub-like search function to your models
|
|
118
|
+
email:
|
|
119
|
+
- mathias@hiasinho.com
|
|
120
|
+
executables: []
|
|
121
|
+
extensions: []
|
|
122
|
+
extra_rdoc_files: []
|
|
123
|
+
files:
|
|
124
|
+
- ".gitignore"
|
|
125
|
+
- ".rspec"
|
|
126
|
+
- ".travis.yml"
|
|
127
|
+
- Appraisals
|
|
128
|
+
- Gemfile
|
|
129
|
+
- Guardfile
|
|
130
|
+
- MIT-LICENSE
|
|
131
|
+
- README.md
|
|
132
|
+
- Rakefile
|
|
133
|
+
- acts_as_explorable.gemspec
|
|
134
|
+
- gemfiles/activerecord_4.0.gemfile
|
|
135
|
+
- gemfiles/activerecord_4.1.gemfile
|
|
136
|
+
- gemfiles/activerecord_4.2.gemfile
|
|
137
|
+
- lib/acts_as_explorable.rb
|
|
138
|
+
- lib/acts_as_explorable/configuration.rb
|
|
139
|
+
- lib/acts_as_explorable/element.rb
|
|
140
|
+
- lib/acts_as_explorable/element/base.rb
|
|
141
|
+
- lib/acts_as_explorable/element/dynamic_filter.rb
|
|
142
|
+
- lib/acts_as_explorable/element/in.rb
|
|
143
|
+
- lib/acts_as_explorable/element/sort.rb
|
|
144
|
+
- lib/acts_as_explorable/explorable.rb
|
|
145
|
+
- lib/acts_as_explorable/ext/string.rb
|
|
146
|
+
- lib/acts_as_explorable/parser.rb
|
|
147
|
+
- lib/acts_as_explorable/query.rb
|
|
148
|
+
- lib/acts_as_explorable/version.rb
|
|
149
|
+
- lib/tasks/acts_as_explorable_tasks.rake
|
|
150
|
+
- spec/factories/players.rb
|
|
151
|
+
- spec/lib/acts_as_explorable/element/dynamic_filter_spec.rb
|
|
152
|
+
- spec/lib/acts_as_explorable/element/in.rb
|
|
153
|
+
- spec/lib/acts_as_explorable/element_spec.rb
|
|
154
|
+
- spec/lib/acts_as_explorable/explorable_spec.rb
|
|
155
|
+
- spec/lib/acts_as_explorable/parser_spec.rb
|
|
156
|
+
- spec/lib/acts_as_explorable/query_spec.rb
|
|
157
|
+
- spec/spec_helper.rb
|
|
158
|
+
- spec/support/database.rb
|
|
159
|
+
- spec/support/database_cleaner.rb
|
|
160
|
+
homepage: https://github.com/hiasinho/acts_as_explorable
|
|
161
|
+
licenses:
|
|
162
|
+
- MIT
|
|
163
|
+
metadata: {}
|
|
164
|
+
post_install_message:
|
|
165
|
+
rdoc_options: []
|
|
166
|
+
require_paths:
|
|
167
|
+
- lib
|
|
168
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
169
|
+
requirements:
|
|
170
|
+
- - ">="
|
|
171
|
+
- !ruby/object:Gem::Version
|
|
172
|
+
version: 2.0.0
|
|
173
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
174
|
+
requirements:
|
|
175
|
+
- - ">="
|
|
176
|
+
- !ruby/object:Gem::Version
|
|
177
|
+
version: '0'
|
|
178
|
+
requirements: []
|
|
179
|
+
rubyforge_project:
|
|
180
|
+
rubygems_version: 2.2.2
|
|
181
|
+
signing_key:
|
|
182
|
+
specification_version: 4
|
|
183
|
+
summary: Adds GitHub-like search function to your models
|
|
184
|
+
test_files: []
|
|
185
|
+
has_rdoc:
|