duck_chain 1.0.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/.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
+