ruby_simple_search 0.0.1 → 0.0.2

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/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/README.md CHANGED
@@ -1,16 +1,45 @@
1
1
  # RubySimpleSearch
2
2
 
3
- RubySimpleSearch allows to search on the table fields.
4
- e.g. string and text fields.
3
+ RubySimpleSearch allows you to search on the table fields (string and text fields)
4
+ very easily.
5
5
 
6
- Sometimes we want to do search on the post's title and content
7
- or user's email, username and description or on other models but in same way.
8
- For those searches we use MySql's or Postgresql's LIKE operator to get the
9
- results. While doing same thing on the differet models you actually add lots of
10
- duplications in your code.
6
+ Mostly on the admin side, we do have a common text field to search the table
7
+ column's data.
8
+
9
+ Sometimes we want to do a search on the title, content and ratings on the post model or
10
+ email, username and description on the user model. For those searches we use MySQL's
11
+ or PostgreSQL's LIKE operator to get the results. While doing the same thing again and again
12
+ on the different models you actually add lots of duplication in your code.
11
13
 
12
14
  To avoid duplicating the same code, use RubySimpleSearch :)
13
15
 
16
+ #### RubySimpleSearch Features:
17
+ - Added like pattern support ('beginning', 'ending', 'containing', 'underscore', 'plain').
18
+ By default pattern is 'containing'
19
+
20
+ ```Ruby
21
+ simple_search_attributes :name, :address, :pattern => :ending
22
+ # It will search like '%york'
23
+
24
+ simple_search_attributes :name, :address, :pattern => :begining
25
+ # It will search like 'york%'
26
+
27
+ simple_search_attributes :name, :address, :pattern => :containing
28
+ # It will search like '%york%'
29
+
30
+ simple_search_attributes :name, :address, :pattern => :underscore
31
+ # It will search like '_o_'
32
+
33
+ simple_search_attributes :name, :address, :pattern => :plain
34
+ # It will search like 'york'
35
+ ```
36
+ - Added **block** support to simple_search method, so user can extend the query as per
37
+ his/her requirements (Now you can operate on the integer/decimal values also)
38
+
39
+ - Added specs
40
+
41
+ - Added exception handler
42
+
14
43
  ## Installation
15
44
 
16
45
  Add this line to your application's Gemfile:
@@ -33,23 +62,46 @@ Define attributes that you want to search through RubySimpleSearch
33
62
  class Post < ActiveActiveRecord::Base
34
63
  include RubySimpleSearch
35
64
 
36
- simple_search_attributes :title, :description
65
+ simple_search_attributes :title, :description, :pattern => :begining
37
66
  end
38
-
39
- class User < < ActiveActiveRecord::Base
67
+ ```
68
+ ```Ruby
69
+ class User < ActiveActiveRecord::Base
40
70
  include RubySimpleSearch
41
71
 
42
72
  simple_search_attributes :email, :username, :address
43
73
  end
44
-
45
- Post.simple_serach('tutorial')
46
- # => posts which have 'tutorial' text in title or in description fields
47
-
48
- User.simple_search('Mechanciles')
49
- # => users which have 'Mechanicles' text in the email, username and in address
50
-
74
+ ```
75
+ While defining simple_search_attributes, don't add integer/decimal data
76
+ attributes to it, instead of this you can do integer/decimal operation
77
+ by passing block to simple search method
78
+ ```Ruby
79
+ Post.simple_search('tuto')
80
+ # => posts which have 'tuto%' text in the title or in the description fields
81
+ ```
82
+ ```Ruby
83
+ User.simple_search('mechanicles')
84
+ # => users which have 'mechanicles' text in the email, username and in address
85
+ ```
86
+ ```Ruby
87
+ User.simple_search('mechanicles') do |search_term|
88
+ ["and address != ?", search_term]
89
+ end
90
+ # => You can pass block to simple_search method so you can extend it as your
91
+ # wish but you need to return an array of valid parameters like you do in #where
92
+ # method
93
+ ```
94
+ ```Ruby
51
95
  Model.simple_search('string')
52
- # => will return ActiveRecord::Relation object
96
+ # => with and without block will return ActiveRecord::Relation object
97
+ ```
98
+ ```Ruby
99
+ Model.simple_search('string').to_sql
100
+ #OR
101
+ User.simple_search('mechanicles') do |search_term|
102
+ ["and address != ?", search_term]
103
+ end.to_sql
104
+ # => will return sql query in string format
53
105
  ```
54
106
  ## Contributing
55
107
 
@@ -1,38 +1,6 @@
1
- # RubySimpleSearch allows to search on the table fields.
2
- # e.g. string and text fields.
3
- #
4
- # Sometimes we want to do search on the post's title and content
5
- # or user's email, username and description or on other models but in same way.
6
- # For those searches we use MySql's or Postgresql's LIKE operator to get the
7
- # results. While doing same thing on the differet models you actually add lots of
8
- # duplications in your code.
9
- #
10
- # To avoid duplicating the same code, use RubySimpleSearch :)
11
- #
12
- # Define attributes that you want to search through RubySimpleSearch
13
- #
14
- # class Post < ActiveActiveRecord::Base
15
- # include RubySimpleSearch
16
- #
17
- # simple_search_attributes :title, :description
18
- # end
19
- #
20
- # class User < < ActiveActiveRecord::Base
21
- # include RubySimpleSearch
22
- #
23
- # simple_search_attributes :email, :username, :address
24
- # end
25
- #
26
- # Post.simple_serach('tutorial')
27
- # # => posts which have tutorial text in title or in description fields
28
- #
29
- # User.simple_search('Mechanciles')
30
- # # => users which have mechanicles text in the email, username and in address
31
- #
32
- # Model.simple_search('string') will return ActiveRecord::Relation object
33
-
34
-
35
1
  require "ruby_simple_search/version"
2
+ require "ruby_simple_search/like_pattern"
3
+ require "ruby_simple_search/errors"
36
4
  require 'active_support/concern'
37
5
 
38
6
  module RubySimpleSearch
@@ -42,30 +10,78 @@ module RubySimpleSearch
42
10
  class_eval do
43
11
  def self.simple_search_attributes(*args)
44
12
  @simple_search_attributes = []
13
+ # default pattern is '%q%'
14
+ @simple_search_pattern = RubySimpleSearch::LIKE_PATTERNS[:containing]
45
15
  args.each do |arg|
46
- @simple_search_attributes << arg
16
+ if !arg.is_a?(Hash)
17
+ @simple_search_attributes << arg
18
+ else
19
+ set_pattern(arg[:pattern]) if arg[:pattern].present?
20
+ end
47
21
  end
48
22
  end
49
23
  end
50
24
  end
51
25
 
52
26
  module ClassMethods
53
- def simple_search(q)
54
- raise ArgumentError, "Argument is not string" unless q.is_a? String
27
+ def simple_search(search_term, &block)
28
+ raise RubySimpleSearch::Error::ATTRIBUTES_MISSING if @simple_search_attributes.blank?
29
+ raise ArgumentError, "Argument is not string" unless search_term.is_a? String
30
+
31
+ sql_query = nil
32
+ extended_query = nil
33
+ sql_query_condition = ""
34
+ sql_query_values = []
55
35
 
56
- query = ""
57
- patterned_text = "%#{q.downcase}%"
36
+ patterned_text = "#{@simple_search_pattern.gsub('q', search_term.try(:downcase))}"
58
37
 
59
38
  @simple_search_attributes.each do |attr|
60
- query += if query == ""
61
- "LOWER(#{attr.to_s}) LIKE ?"
62
- else
63
- " OR LOWER(#{attr.to_s}) LIKE ?"
64
- end
39
+ sql_query_condition << set_sql_query_condition(attr, sql_query_condition)
40
+ sql_query_values << patterned_text
41
+ end
42
+
43
+ if block.is_a? Proc
44
+ sql_query_condition = "(#{sql_query_condition})"
45
+ extended_query = block.call(search_term)
46
+ end
47
+
48
+ if !extended_query.nil?
49
+ sql_query_values, sql_query_condition = extend_simple_search(extended_query,
50
+ sql_query_condition,
51
+ sql_query_values)
52
+ end
53
+ sql_query = [sql_query_condition, sql_query_values]
54
+
55
+ where(sql_query.try(:flatten))
56
+ end
57
+
58
+ private
59
+
60
+ def set_pattern(pattern)
61
+ pattern = RubySimpleSearch::LIKE_PATTERNS[pattern.to_sym] rescue nil
62
+ raise RubySimpleSearch::Error::INVALID_PATTERN if pattern.nil?
63
+ @simple_search_pattern = pattern
64
+ end
65
+
66
+ def extend_simple_search(extended_query, sql_query_condition, sql_query_values)
67
+ raise RubySimpleSearch::Error::INVALID_TYPE unless extended_query.is_a?(Array)
68
+ extended_query_condition = extended_query[0]
69
+ extended_query_values = extended_query - [extended_query[0]]
65
70
 
71
+ if extended_query_condition.count('?') != (extended_query_values.size)
72
+ raise RubySimpleSearch::Error::INVALID_CONDITION
66
73
  end
67
74
 
68
- where([query] + Array.new(@simple_search_attributes.size, patterned_text))
75
+ sql_query_condition = [sql_query_condition, extended_query_condition].join(' ')
76
+ sql_query_values = sql_query_values + extended_query_values
77
+
78
+ [sql_query_values, sql_query_condition]
79
+ end
80
+
81
+ def set_sql_query_condition(attr, sql_query_condition)
82
+ return "LOWER(#{attr.to_s}) LIKE ?" if sql_query_condition.blank?
83
+ " OR LOWER(#{attr.to_s}) LIKE ?"
69
84
  end
85
+
70
86
  end
71
87
  end
@@ -0,0 +1,10 @@
1
+ require "ruby_simple_search/errors"
2
+
3
+ module RubySimpleSearch
4
+ module Error
5
+ ATTRIBUTES_MISSING = "Simple search attributes are missing"
6
+ INVALID_TYPE = "Extended query is not an array type"
7
+ INVALID_CONDITION = "Extended query's array conditions are wrong"
8
+ INVALID_PATTERN = "Pattern is wrong. it should be in the list #{RubySimpleSearch::LIKE_PATTERNS.keys}"
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+ module RubySimpleSearch
2
+ LIKE_PATTERNS = { plain: 'q', underscore: '_q_', beginning: 'q%',
3
+ ending: '%q', containing: '%q%'}
4
+ end
@@ -1,3 +1,3 @@
1
1
  module RubySimpleSearch
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -14,6 +14,8 @@ Gem::Specification.new do |gem|
14
14
 
15
15
  gem.add_dependency "activesupport", ">= 3.0.0"
16
16
  gem.add_dependency "activerecord", ">= 3.0.0"
17
+ gem.add_dependency "sqlite3"
18
+ gem.add_development_dependency "rspec"
17
19
 
18
20
  gem.files = `git ls-files`.split($/)
19
21
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
data/spec/lib/user.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'active_record'
2
+ require_relative "../../lib/ruby_simple_search.rb"
3
+
4
+ class User < ActiveRecord::Base
5
+ include RubySimpleSearch
6
+
7
+ simple_search_attributes :name, :email, :contact, :address
8
+ end
data/spec/lib/user2.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'active_record'
2
+ require_relative "../../lib/ruby_simple_search.rb"
3
+
4
+ class User2 < ActiveRecord::Base
5
+ include RubySimpleSearch
6
+ end
@@ -0,0 +1,40 @@
1
+ require 'rspec'
2
+ require 'active_record'
3
+
4
+ ActiveRecord::Migration.verbose = false
5
+
6
+ RSpec.configure do |config|
7
+ config.before(:all) do
8
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
9
+ create_database
10
+ User.create :email => "alice@example.com",
11
+ :name => "alice", :address => "usa",
12
+ :contact => '12345', :age => 60
13
+ User.create :email => "bob@example.com",
14
+ :name => "bob", :address => "usa",
15
+ :contact => "56789", :age => 26
16
+ end
17
+
18
+ config.after(:all) do
19
+ drop_database
20
+ end
21
+ end
22
+
23
+ def create_database
24
+ ActiveRecord::Schema.define(:version => 1) do
25
+ create_table :users do |t|
26
+ t.string :name
27
+ t.text :address
28
+ t.text :contact
29
+ t.string :email
30
+ t.integer :age
31
+ t.timestamps
32
+ end
33
+ end
34
+ end
35
+
36
+ def drop_database
37
+ ActiveRecord::Base.connection.tables.each do |table|
38
+ ActiveRecord::Base.connection.drop_table(table)
39
+ end
40
+ end
data/spec/user_spec.rb ADDED
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+ require_relative "../spec/lib/user.rb"
3
+ require_relative "../spec/lib/user2.rb"
4
+
5
+ describe User do
6
+
7
+ describe ".simple_search_attributes" do
8
+
9
+ it "returns an exception if simple_search_attributes is not called while loading the model" do
10
+ expect { User2.simple_search('usa') }.to raise_error(RubySimpleSearch::Error::ATTRIBUTES_MISSING)
11
+ end
12
+
13
+ it "sets simple_search_attributes" do
14
+ User2.simple_search_attributes :name, :contact
15
+ expect(User2.instance_variable_get("@simple_search_attributes")).to eq([:name, :contact])
16
+ end
17
+
18
+ it "has default pattern" do
19
+ User2.simple_search_attributes :name, :contact
20
+ expect(User2.instance_variable_get("@simple_search_pattern")).to eq('%q%')
21
+ end
22
+
23
+ it "can have patterns like plain, beginning, ending, containing and underscore" do
24
+ User2.simple_search_attributes :name, :contact, :pattern => :plain
25
+ expect(User2.instance_variable_get("@simple_search_pattern")).to eq('q')
26
+ User2.simple_search_attributes :name, :contact, :pattern => :beginning
27
+ expect(User2.instance_variable_get("@simple_search_pattern")).to eq('q%')
28
+ User2.simple_search_attributes :name, :contact, :pattern => :ending
29
+ expect(User2.instance_variable_get("@simple_search_pattern")).to eq('%q')
30
+ User2.simple_search_attributes :name, :contact, :pattern => :containing
31
+ expect(User2.instance_variable_get("@simple_search_pattern")).to eq('%q%')
32
+ User2.simple_search_attributes :name, :contact, :pattern => :underscore
33
+ expect(User2.instance_variable_get("@simple_search_pattern")).to eq('_q_')
34
+ end
35
+
36
+ it "should raise an exception if pattern is wrong" do
37
+ expect{ User2.simple_search_attributes :name, :pattern => 'wrong' }.to raise_error(RubySimpleSearch::Error::INVALID_PATTERN)
38
+ end
39
+ end
40
+
41
+ describe ".simple_search" do
42
+ context "Simple" do
43
+ it "searches users whose name are 'alice'" do
44
+ user = User.find_by_name('alice')
45
+ users = User.simple_search('alice')
46
+ users.should include(user)
47
+ end
48
+
49
+ it "returns empty records if contact number does not exist" do
50
+ users = User.simple_search('343434')
51
+ users.should be_empty
52
+ end
53
+
54
+ it "searches user records if user belongs to 'USA'" do
55
+ users = User.where(:address => 'usa')
56
+ searched_users = User.simple_search('usa')
57
+ expect(users.to_a).to eq(searched_users.to_a)
58
+ end
59
+
60
+ it "searches the records with beginning pattern" do
61
+ users = User.where("name like ?", 'bo%')
62
+ User.simple_search_attributes :name, :contact, :address, :pattern => :beginning
63
+ searched_users = User.simple_search('bo')
64
+ expect(users.count).to eq(searched_users.count)
65
+ end
66
+
67
+ it "searches the records with ending pattern" do
68
+ users = User.where("name like ?", '%ce')
69
+ User.simple_search_attributes :name, :contact, :address, :pattern => :ending
70
+ searched_users = User.simple_search('ce')
71
+ expect(users.count).to eq(searched_users.count)
72
+ end
73
+
74
+ it "searches the records with underscore pattern" do
75
+ users = User.where("name like ?", 'ce')
76
+ User.simple_search_attributes :name, :contact, :address, :pattern => :underscore
77
+ searched_users = User.simple_search('ce')
78
+ expect(users.count).to eq(searched_users.count)
79
+ end
80
+
81
+ it "searches the records with plain pattern" do
82
+ users = User.where("name like ?", 'bob')
83
+ User.simple_search_attributes :name, :contact, :address, :pattern => :plain
84
+ searched_users = User.simple_search('bob')
85
+ expect(users.count).to eq(searched_users.count)
86
+ end
87
+ end
88
+
89
+ context "Extendable" do
90
+ it "returns users who live in usa and their age shoule be greater than 50" do
91
+ User.simple_search_attributes :name, :contact, :address, :pattern => :plain
92
+ users = User.where(:age => 60)
93
+ searched_users = User.simple_search('usa') do |search_term|
94
+ ['AND age > ?', 50]
95
+ end
96
+ expect(users.to_a).to eq(searched_users.to_a)
97
+ end
98
+
99
+ it "returns exception if array condition is wrong in simple_search block" do
100
+ expect{ User.simple_search('usa') do |search_term|
101
+ ['AND age > ?', 50, 60]
102
+ end }.to raise_error(RubySimpleSearch::Error::INVALID_CONDITION)
103
+ end
104
+
105
+ it "returns exception if return value is not an array type" do
106
+ expect{ User.simple_search('usa') do |search_term|
107
+ "Wrong return"
108
+ end }.to raise_error(RubySimpleSearch::Error::INVALID_TYPE)
109
+ end
110
+ end
111
+ end
112
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_simple_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-18 00:00:00.000000000 Z
12
+ date: 2013-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -43,6 +43,38 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: 3.0.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: sqlite3
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
46
78
  description: It will search on the attributes that you provided to simple_search_attributes
47
79
  method
48
80
  email:
@@ -52,13 +84,20 @@ extensions: []
52
84
  extra_rdoc_files: []
53
85
  files:
54
86
  - .gitignore
87
+ - .rspec
55
88
  - Gemfile
56
89
  - LICENSE.txt
57
90
  - README.md
58
91
  - Rakefile
59
92
  - lib/ruby_simple_search.rb
93
+ - lib/ruby_simple_search/errors.rb
94
+ - lib/ruby_simple_search/like_pattern.rb
60
95
  - lib/ruby_simple_search/version.rb
61
96
  - ruby_simple_search.gemspec
97
+ - spec/lib/user.rb
98
+ - spec/lib/user2.rb
99
+ - spec/spec_helper.rb
100
+ - spec/user_spec.rb
62
101
  homepage: https://github.com/mechanicles/ruby_simple_search
63
102
  licenses: []
64
103
  post_install_message:
@@ -79,8 +118,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
118
  version: '0'
80
119
  requirements: []
81
120
  rubyforge_project:
82
- rubygems_version: 1.8.24
121
+ rubygems_version: 1.8.25
83
122
  signing_key:
84
123
  specification_version: 3
85
124
  summary: Ruby simple search for ActiveRecord
86
- test_files: []
125
+ test_files:
126
+ - spec/lib/user.rb
127
+ - spec/lib/user2.rb
128
+ - spec/spec_helper.rb
129
+ - spec/user_spec.rb