duck_chain 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,2 @@
1
+ Version 1.0.0
2
+ * First release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in duck_chain.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2011 Tony Drake
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.
21
+
data/README.rdoc ADDED
@@ -0,0 +1,85 @@
1
+ = duck_chain
2
+
3
+ == Intro
4
+ This gem's purpose is to generate basic chainable search methods on models in Rails 3 similar to searchlogic's dynamic named scopes.
5
+
6
+ duck_chain's original purpose is to help with the transition from Rails 2 to 3. A lot of projects use searchlogic, and while metasearch
7
+ is a fine replacement, it doesn't provide the dynamic named scopes (ie Post.title_equals("foobar").content_like("I like pie"). To help with the
8
+ transition, duck_chain extends ActiveRecord and creates extra chainable model methods for attributes you specifiy which act similar to the basic
9
+ searchlogic named scopes. The methods simply return Arel where cluases so you can chain them with other methods.
10
+
11
+ Only the basic single table methods are supported (eq, not_equal, gte, like, etc.). Meaning you can't do Post.post_comments_title_eq("This blog sux").
12
+ Legacy code like that should be converted into an Arel where method, metasearch search method, or whatever you decide to go with for Rails 3. Again,
13
+ the gem was built to help with the transition and provide some of the basic search methods people using searchlogic are used to in Rails 3. Plus, I personally like typing out
14
+ Post.created_at_gte(Time.now).content_like("I like shorts. They're comfortable and easy to wear.") more than Post.where(['created_at >= ?', Time.now]).where("content LIKE '%I like shorts. They're comfortable and easy to wear.%'").
15
+ Just seems a little clearer this way. :)
16
+
17
+ == Setup
18
+ Include the gem in your GemFile like any other gem.
19
+
20
+ == Usage
21
+ Consider the following model...
22
+ class Post < ActiveRecord::Base
23
+ # Fields:
24
+ # id:integer
25
+ # title:string
26
+ # content:text
27
+ # url:string
28
+ # comment_counter:integer
29
+ # created_at:datetime
30
+ # updated_at:datetime
31
+ end
32
+
33
+ ==== Use all search methods for selected attributes
34
+ To have duck_chain bind to the title, content, and url attributes of the model...
35
+ class Post < ActiveRecord::Base
36
+ duck_chain :content, 'title', :url
37
+ # Note you can use symbols or strings in your list of attributes
38
+ end
39
+
40
+ Calling duck_chain creates a bunch of chainable methods for the Post model for the content, title, and url attributes...
41
+
42
+ Example new methods related to the title attribute:
43
+
44
+ <i>The following <b>'eq'</b> methods can accept a string, array, or range</i>
45
+ * title_eq
46
+ * title_equals
47
+ * title_is
48
+ * title_in
49
+ * title_neq
50
+ * title_not_equal
51
+ * title_is_not
52
+ * title_does_not_equal
53
+ * title_not_in
54
+ <i>The following <b>'like'</b> methods should only be passed a string</i>
55
+ * title_like
56
+ * title_begins_with
57
+ * title_ends_with
58
+ * title_not_like
59
+ * title_not_begin_with
60
+ * title_not_end_with
61
+ <i>The following <b>'range'</b> methods should only be passed a string</i>
62
+ * title_gt
63
+ * title_greater_than
64
+ * title_gte
65
+ * title_greater_than_or_equal_to
66
+ * title_lt
67
+ * title_less_than
68
+ * title_lte
69
+ * title_less_than_or_equal_to
70
+
71
+ Then, you can just use the methods in your code like you did with searchlogic...
72
+ Post.title_eq("Foobar").where(...).content_like("Blah")
73
+
74
+ ==== Use only certain search methods for selected attributes
75
+ There might be some cases where you'd rather just only bind the 'eq' methods to an attribute rather than all of them...
76
+ class Post < ActiveRecord::Base
77
+ # Will only create the _eq, _is, _neq, _in, etc. methods
78
+ duck_chain_eq :content, 'title', :url
79
+ end
80
+
81
+ You can also create only the 'like' and 'range' methods in a similar fasion...
82
+ class Post < ActiveRecord::Base
83
+ duck_chain_like :content
84
+ duck_chain_range :created_at
85
+ end
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake/rdoctask'
4
+ desc 'Generate RDoc documentation for the will_paginate plugin.'
5
+ Rake::RDocTask.new(:rdoc) do |rdoc|
6
+ rdoc.rdoc_files.include('README.rdoc', 'LICENSE', 'CHANGELOG.rdoc').include('lib/**/*.rb').exclude('lib/duck_chain/version.rb')
7
+
8
+ rdoc.main = "README.rdoc" # page to start on
9
+ rdoc.title = "duck_chain documentation"
10
+
11
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
12
+ rdoc.options << '--inline-source' << '--charset=UTF-8'
13
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "duck_chain/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "duck_chain"
7
+ s.version = DuckChain::VERSION
8
+
9
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
10
+
11
+ s.authors = ["Tony Drake"]
12
+ s.email = ["t27duck@gmail.com"]
13
+ # s.homepage = ""
14
+ s.summary = %q{Because I like chaining easy to read search methods with ActiveRecord thankyouverymuch}
15
+ s.description = %q{A simple Rails 3 Gem that extends ActiveRecord. Let's you specify model attributes to dynamically create search methods similar to searchlogic's dynamic named scopes. It can be used to help Rails 2 projects with searchlogic migrate to Rails 3 with metasearch a little easier.}
16
+
17
+ s.rubyforge_project = "duck_chain"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+
24
+ s.add_dependency(%q<activerecord>, [">= 3.0.0"])
25
+ end
@@ -0,0 +1,32 @@
1
+ module DuckChain
2
+
3
+ # Methods that extend ActiveRecord and allows duck_chain to work
4
+ module ActiveRecordExtensions
5
+
6
+ # The generic call which will generate all methods for the model
7
+ def duck_chain(*model_attributes)
8
+ Toolset.create_eq_methods(model_attributes)
9
+ Toolset.create_like_methods(model_attributes)
10
+ Toolset.create_range_methods(model_attributes)
11
+ end
12
+
13
+ # Takes the list of model attributes calls the create method from DuckChain::Toolset
14
+ # to generate the 'eq' methods
15
+ def duck_chain_eq(*model_attributes)
16
+ Toolset.create_eq_methods(model_attributes)
17
+ end
18
+
19
+ # Takes the list of model attributes calls the create method from DuckChain::Toolset
20
+ # to generate the 'list' methods
21
+ def duck_chain_like(*model_attributes)
22
+ Toolset.create_like_methods(model_attributes)
23
+ end
24
+
25
+ # Takes the list of model attributes calls the create method from DuckChain::Toolset
26
+ # to generate the 'range' methods
27
+ def duck_chain_range(*model_attributes)
28
+ Toolset.create_range_methods(model_attributes)
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,99 @@
1
+ module DuckChain
2
+ module Toolset
3
+ # Generic helper method that ensures whatever is passed into it is an array.
4
+ # If it's not, make it one.
5
+ def self.set_as_array(value)
6
+ value.is_a?(Array) ? value : [value]
7
+ end
8
+
9
+ # Creates 'eq' class methods for the model
10
+ # Ex:: Post.title_eq("Why do my feet smell?")
11
+ # Methods created include...
12
+ # * eq
13
+ # * equals
14
+ # * is
15
+ # * in
16
+ # * neq
17
+ # * not_equal
18
+ # * is_not
19
+ # * does_not_equal
20
+ # * not_in
21
+ # A string, array, or a range may be passed into these created methods.
22
+ # Passing an array or range will result in a IN clause in the resulting SQL.
23
+ def self.create_eq_methods(model_attributes)
24
+ Toolset.set_as_array(model_attributes).each do |m|
25
+ ['eq','equals','is','in'].each do |suffix|
26
+ self.class.send(:define_method, "#{m}_#{suffix}", Proc.new{ |search_term|
27
+ if search_term.is_a?(Array) || search_term.is_a?(Range)
28
+ where(["#{m} IN (?)", search_term])
29
+ else
30
+ where(["#{m} = ?", search_term])
31
+ end
32
+ }
33
+ )
34
+ end
35
+
36
+ ['neq','not_equal','is_not','does_not_equal','not_in'].each do |suffix|
37
+ self.class.send(:define_method, "#{m}_#{suffix}", Proc.new{ |search_term|
38
+ if search_term.is_a?(Array) || search_term.is_a?(Range)
39
+ where(["? NOT IN (?)", m, search_term])
40
+ else
41
+ where(["? != ?", m, search_term])
42
+ end
43
+ }
44
+ )
45
+ end
46
+ end
47
+ end
48
+
49
+ # Creates 'like' class methods for the model
50
+ # Ex:: Post.title_like("Foo")
51
+ # Methods created include...
52
+ # * like
53
+ # * begins_with
54
+ # * ends_with
55
+ # * not_like
56
+ # * not_begin_with
57
+ # * not_end_with
58
+ def self.create_like_methods(model_attributes)
59
+ Toolset.set_as_array(model_attributes).each do |m|
60
+ self.class.send(:define_method, "#{m}_like", Proc.new{ |search_term| where(["? LIKE (?)", m, "%#{search_term}%"])} )
61
+ self.class.send(:define_method, "#{m}_begins_with", Proc.new{ |search_term| where(["? LIKE (?)", m, "#{search_term}%"])} )
62
+ self.class.send(:define_method, "#{m}_ends_with", Proc.new{ |search_term| where(["? LIKE (?)", m, "%#{search_term}"])} )
63
+
64
+ self.class.send(:define_method, "#{m}_not_like", Proc.new{ |search_term| where(["? NOT LIKE (?)", m, "%#{search_term}%"])} )
65
+ self.class.send(:define_method, "#{m}_not_begin_with", Proc.new{ |search_term| where(["? NOT LIKE (?)", m, "#{search_term}%"])} )
66
+ self.class.send(:define_method, "#{m}_not_end_with", Proc.new{ |search_term| where(["? NOT LIKE (?)", m, "%#{search_term}"])} )
67
+ end
68
+ end
69
+
70
+ # Creates 'range' class methods for the model
71
+ # Ex:: Post.comment_counter_gt(5)
72
+ # Methods created include...
73
+ # * gt
74
+ # * greater_than
75
+ # * gte
76
+ # * greater_than_or_equal_to
77
+ # * lt
78
+ # * less_then
79
+ # * lte
80
+ # * less_than_or_equal_to
81
+ def self.create_range_methods(model_attributes)
82
+ Toolset.set_as_array(model_attributes).each do |m|
83
+ ['gt','greater_than'].each do |suffix|
84
+ self.class.send(:define_method, "#{m}_#{suffix}", Proc.new{ |search_term| where(['? > ?', m, search_term])} )
85
+ end
86
+ ['gte','greater_than_or_equal_to'].each do |suffix|
87
+ self.class.send(:define_method, "#{m}_#{suffix}", Proc.new{ |search_term| where(['? >= ?', m, search_term])} )
88
+ end
89
+ ['lt','less_than'].each do |suffix|
90
+ self.class.send(:define_method, "#{m}_#{suffix}", Proc.new{ |search_term| where(['? < ?', m, search_term])} )
91
+ end
92
+ ['lte','less_than_or_equal_to'].each do |suffix|
93
+ self.class.send(:define_method, "#{m}_#{suffix}", Proc.new{ |search_term| where(['? <= ?', m, search_term])} )
94
+ end
95
+ end
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,3 @@
1
+ module DuckChain
2
+ VERSION = "1.0.0"
3
+ end
data/lib/duck_chain.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "duck_chain/version"
2
+ require "duck_chain/toolset"
3
+ require "duck_chain/active_record_extensions"
4
+
5
+ ActiveRecord::Base.extend DuckChain::ActiveRecordExtensions
6
+
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: duck_chain
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Tony Drake
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-06-14 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activerecord
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ - 0
34
+ version: 3.0.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: A simple Rails 3 Gem that extends ActiveRecord. Let's you specify model attributes to dynamically create search methods similar to searchlogic's dynamic named scopes. It can be used to help Rails 2 projects with searchlogic migrate to Rails 3 with metasearch a little easier.
38
+ email:
39
+ - t27duck@gmail.com
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - .gitignore
48
+ - CHANGELOG.rdoc
49
+ - Gemfile
50
+ - LICENSE
51
+ - README.rdoc
52
+ - Rakefile
53
+ - duck_chain.gemspec
54
+ - lib/duck_chain.rb
55
+ - lib/duck_chain/active_record_extensions.rb
56
+ - lib/duck_chain/toolset.rb
57
+ - lib/duck_chain/version.rb
58
+ has_rdoc: true
59
+ homepage:
60
+ licenses: []
61
+
62
+ post_install_message:
63
+ rdoc_options: []
64
+
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">"
80
+ - !ruby/object:Gem::Version
81
+ hash: 25
82
+ segments:
83
+ - 1
84
+ - 3
85
+ - 1
86
+ version: 1.3.1
87
+ requirements: []
88
+
89
+ rubyforge_project: duck_chain
90
+ rubygems_version: 1.6.2
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: Because I like chaining easy to read search methods with ActiveRecord thankyouverymuch
94
+ test_files: []
95
+