searchgasm 0.9.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.
@@ -0,0 +1,124 @@
1
+
2
+ # Gem::Specification for Searchgasm-0.9.0
3
+ # Originally generated by Echoe
4
+
5
+ --- !ruby/object:Gem::Specification
6
+ name: searchgasm
7
+ version: !ruby/object:Gem::Version
8
+ version: 0.9.0
9
+ platform: ruby
10
+ authors:
11
+ - Ben Johnson of Binary Logic
12
+ autorequire:
13
+ bindir: bin
14
+
15
+ date: 2008-09-01 00:00:00 -04:00
16
+ default_executable:
17
+ dependencies:
18
+ - !ruby/object:Gem::Dependency
19
+ name: activerecord
20
+ type: :runtime
21
+ version_requirement:
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: "0"
27
+ version:
28
+ - !ruby/object:Gem::Dependency
29
+ name: echoe
30
+ type: :development
31
+ version_requirement:
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: "0"
37
+ version:
38
+ description: Makes ActiveRecord searching easier, robust, and powerful. Automatic conditions, pagination support, object based searching, and more.
39
+ email: bjohnson@binarylogic.com
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files:
45
+ - CHANGELOG
46
+ - lib/searchgasm/active_record/associations.rb
47
+ - lib/searchgasm/active_record/base.rb
48
+ - lib/searchgasm/active_record/protection.rb
49
+ - lib/searchgasm/helpers.rb
50
+ - lib/searchgasm/search/base.rb
51
+ - lib/searchgasm/search/condition.rb
52
+ - lib/searchgasm/search/conditions.rb
53
+ - lib/searchgasm/search/utilities.rb
54
+ - lib/searchgasm/version.rb
55
+ - lib/searchgasm.rb
56
+ - README.mdown
57
+ files:
58
+ - CHANGELOG
59
+ - init.rb
60
+ - lib/searchgasm/active_record/associations.rb
61
+ - lib/searchgasm/active_record/base.rb
62
+ - lib/searchgasm/active_record/protection.rb
63
+ - lib/searchgasm/helpers.rb
64
+ - lib/searchgasm/search/base.rb
65
+ - lib/searchgasm/search/condition.rb
66
+ - lib/searchgasm/search/conditions.rb
67
+ - lib/searchgasm/search/utilities.rb
68
+ - lib/searchgasm/version.rb
69
+ - lib/searchgasm.rb
70
+ - Manifest
71
+ - MIT-LICENSE
72
+ - Rakefile
73
+ - README.mdown
74
+ - test/fixtures/accounts.yml
75
+ - test/fixtures/orders.yml
76
+ - test/fixtures/users.yml
77
+ - test/libs/acts_as_tree.rb
78
+ - test/libs/rexml_fix.rb
79
+ - test/test_active_record_associations.rb
80
+ - test/test_active_record_base.rb
81
+ - test/test_active_record_protection.rb
82
+ - test/test_helper.rb
83
+ - test/test_searchgasm_base.rb
84
+ - test/test_searchgasm_condition.rb
85
+ - test/test_searchgasm_conditions.rb
86
+ - searchgasm.gemspec
87
+ has_rdoc: true
88
+ homepage: http://github.com/binarylogic/searchgasm
89
+ post_install_message:
90
+ rdoc_options:
91
+ - --line-numbers
92
+ - --inline-source
93
+ - --title
94
+ - Searchgasm
95
+ - --main
96
+ - README.mdown
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: "0"
104
+ version:
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "="
108
+ - !ruby/object:Gem::Version
109
+ version: "1.2"
110
+ version:
111
+ requirements: []
112
+
113
+ rubyforge_project: searchgasm
114
+ rubygems_version: 1.2.0
115
+ specification_version: 2
116
+ summary: Orgasmic ActiveRecord searching
117
+ test_files:
118
+ - test/test_active_record_associations.rb
119
+ - test/test_active_record_base.rb
120
+ - test/test_active_record_protection.rb
121
+ - test/test_helper.rb
122
+ - test/test_searchgasm_base.rb
123
+ - test/test_searchgasm_condition.rb
124
+ - test/test_searchgasm_conditions.rb
@@ -0,0 +1,15 @@
1
+ binary_logic:
2
+ id: 1
3
+ name: "Binary Logic"
4
+ active: true
5
+
6
+ neco:
7
+ id: 2
8
+ name: "NECO"
9
+ active: false
10
+
11
+ binary_fun:
12
+ id: 3
13
+ name: "Binary Fun"
14
+ active: true
15
+
@@ -0,0 +1,14 @@
1
+ bens_order:
2
+ id: 1
3
+ user_id: 1
4
+ total: 500.23
5
+ description: A bunch of apple products, etc.
6
+ receipt: some binary text
7
+
8
+ drews_order:
9
+ id: 2
10
+ user_id: 2
11
+ total: 2.12
12
+ description: Some more apple projects, ipod, etc
13
+ receipt: some more binary text
14
+
@@ -0,0 +1,27 @@
1
+ ben:
2
+ id: 1
3
+ account_id: 1
4
+ parent_id: null
5
+ first_name: Ben
6
+ last_name: Johnson
7
+ active: true
8
+ bio: Totally awesome!
9
+
10
+ drew:
11
+ id: 2
12
+ account_id: 2
13
+ parent_id: 1
14
+ first_name: Drew
15
+ last_name: Mills
16
+ active: false
17
+ bio: Totally not awesome!
18
+
19
+ jennifer:
20
+ id: 3
21
+ account_id: 1
22
+ parent_id: 2
23
+ first_name: Jennifer
24
+ last_name: Hopkins
25
+ active: false
26
+ bio: Totally not awesome at all!
27
+
@@ -0,0 +1,98 @@
1
+ module ActiveRecord
2
+ module Acts
3
+ module Tree
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ # Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children
9
+ # association. This requires that you have a foreign key column, which by default is called +parent_id+.
10
+ #
11
+ # class Category < ActiveRecord::Base
12
+ # acts_as_tree :order => "name"
13
+ # end
14
+ #
15
+ # Example:
16
+ # root
17
+ # \_ child1
18
+ # \_ subchild1
19
+ # \_ subchild2
20
+ #
21
+ # root = Category.create("name" => "root")
22
+ # child1 = root.children.create("name" => "child1")
23
+ # subchild1 = child1.children.create("name" => "subchild1")
24
+ #
25
+ # root.parent # => nil
26
+ # child1.parent # => root
27
+ # root.children # => [child1]
28
+ # root.children.first.children.first # => subchild1
29
+ #
30
+ # In addition to the parent and children associations, the following instance methods are added to the class
31
+ # after calling <tt>acts_as_tree</tt>:
32
+ # * <tt>siblings</tt> - Returns all the children of the parent, excluding the current node (<tt>[subchild2]</tt> when called on <tt>subchild1</tt>)
33
+ # * <tt>self_and_siblings</tt> - Returns all the children of the parent, including the current node (<tt>[subchild1, subchild2]</tt> when called on <tt>subchild1</tt>)
34
+ # * <tt>ancestors</tt> - Returns all the ancestors of the current node (<tt>[child1, root]</tt> when called on <tt>subchild2</tt>)
35
+ # * <tt>root</tt> - Returns the root of the current node (<tt>root</tt> when called on <tt>subchild2</tt>)
36
+ module ClassMethods
37
+ # Configuration options are:
38
+ #
39
+ # * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
40
+ # * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
41
+ # * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
42
+ def acts_as_tree(options = {})
43
+ configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil }
44
+ configuration.update(options) if options.is_a?(Hash)
45
+
46
+ belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
47
+ has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => :destroy
48
+
49
+ class_eval <<-EOV
50
+ include ActiveRecord::Acts::Tree::InstanceMethods
51
+
52
+ def self.roots
53
+ find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
54
+ end
55
+
56
+ def self.root
57
+ find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
58
+ end
59
+ EOV
60
+ end
61
+ end
62
+
63
+ module InstanceMethods
64
+ # Returns list of ancestors, starting from parent until root.
65
+ #
66
+ # subchild1.ancestors # => [child1, root]
67
+ def ancestors
68
+ node, nodes = self, []
69
+ nodes << node = node.parent while node.parent
70
+ nodes
71
+ end
72
+
73
+ # Returns the root node of the tree.
74
+ def root
75
+ node = self
76
+ node = node.parent while node.parent
77
+ node
78
+ end
79
+
80
+ # Returns all siblings of the current node.
81
+ #
82
+ # subchild1.siblings # => [subchild2]
83
+ def siblings
84
+ self_and_siblings - [self]
85
+ end
86
+
87
+ # Returns all siblings and a reference to the current node.
88
+ #
89
+ # subchild1.self_and_siblings # => [subchild1, subchild2]
90
+ def self_and_siblings
91
+ parent ? parent.children : self.class.roots
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ ActiveRecord::Base.send :include, ActiveRecord::Acts::Tree
@@ -0,0 +1,14 @@
1
+ module REXML
2
+ module Formatters
3
+ class Pretty < Default
4
+ private
5
+ def wrap(string, width)
6
+ # Recursivly wrap string at width.
7
+ return string if string.length <= width
8
+ place = string.rindex(/\s+/, width) # Position in string with last ' ' before cutoff
9
+ return string if place.nil?
10
+ return string[0,place] + "\n" + wrap(string[place+1..-1], width)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestActiveRecordAssociations < Test::Unit::TestCase
4
+ fixtures :accounts, :users, :orders
5
+
6
+ def setup
7
+ setup_db
8
+ load_fixtures
9
+ end
10
+
11
+ def teardown
12
+ teardown_db
13
+ end
14
+
15
+ def test_build_search
16
+ search = Account.find(1).users.build_search
17
+ assert_kind_of BinaryLogic::Searchgasm::Search::Base, search
18
+ assert_equal User, search.klass
19
+ assert_equal "\"users\".account_id = 1", search.conditions.scope
20
+
21
+ search.conditions.first_name_contains = "Ben"
22
+ assert_equal({:conditions => ["(\"users\".\"first_name\" LIKE ?) AND (\"users\".account_id = 1)", "%Ben%"]}, search.sanitize)
23
+ end
24
+
25
+ def test_searching
26
+ assert_equal [User.find(1)], Account.find(1).users.all(:conditions => {:first_name_begins_with => "Ben"})
27
+ assert_equal [User.find(1)], Account.find(1).users.find(:all, :conditions => {:first_name_begins_with => "Ben"})
28
+ assert_equal User.find(1), Account.find(1).users.first(:conditions => {:first_name_begins_with => "Ben"})
29
+ assert_equal User.find(1), Account.find(1).users.find(:first, :conditions => {:first_name_begins_with => "Ben"})
30
+ assert_equal [], Account.find(1).users.all(:conditions => {:first_name_begins_with => "Ben"}, :per_page => 20, :page => 5)
31
+ end
32
+
33
+ def test_calculations
34
+ assert_equal 1, Account.find(1).users.count(:conditions => {:first_name_begins_with => "Ben"})
35
+ assert_equal 1, Account.find(1).users.sum("id", :conditions => {:first_name_begins_with => "Ben"})
36
+ assert_equal 1, Account.find(1).users.average("id", :conditions => {:first_name_begins_with => "Ben"})
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestActiveRecordBase < Test::Unit::TestCase
4
+ fixtures :accounts, :users, :orders
5
+
6
+ def setup
7
+ setup_db
8
+ load_fixtures
9
+ end
10
+
11
+ def teardown
12
+ teardown_db
13
+ end
14
+
15
+ def test_valid_find_options
16
+ assert_equal [ :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :from, :lock ], ActiveRecord::Base.valid_find_options
17
+ end
18
+
19
+ def test_build_search
20
+ search = Account.build_search(:conditions => {:name_keywords => "awesome"}, :page => 2, :per_page => 15)
21
+ assert_kind_of BinaryLogic::Searchgasm::Search::Base, search
22
+ assert_equal Account, search.klass
23
+ assert_equal "awesome", search.conditions.name_keywords
24
+ assert_equal 2, search.page
25
+ assert_equal 15, search.per_page
26
+ end
27
+
28
+ def test_searching
29
+ assert_equal Account.find(1, 3), Account.all(:conditions => {:name_contains => "Binary"})
30
+ assert_equal [Account.find(1)], Account.all(:conditions => {:name_contains => "Binary", :users => {:first_name_starts_with => "Ben"}})
31
+ assert_equal [], Account.all(:conditions => {:name_contains => "Binary", :users => {:first_name_starts_with => "Ben", :last_name => "Mills"}})
32
+
33
+ read_only_accounts = Account.all(:conditions => {:name_contains => "Binary"}, :readonly => true)
34
+ assert read_only_accounts.first.readonly?
35
+
36
+ assert_equal Account.find(1, 3), Account.all(:conditions => {:name_contains => "Binary"}, :page => 2)
37
+ assert_equal [], Account.all(:conditions => {:name_contains => "Binary"}, :page => 2, :per_page => 20)
38
+ end
39
+
40
+ def test_counting
41
+ assert_equal 2, Account.count(:conditions => {:name_contains => "Binary"})
42
+ assert_equal 1, Account.count(:conditions => {:name_contains => "Binary", :users => {:first_name_contains => "Ben"}})
43
+ end
44
+
45
+ def test_scoping
46
+ assert_equal({}, Account.send(:scope, :find))
47
+ end
48
+ end
File without changes
@@ -0,0 +1,78 @@
1
+ require "test/unit"
2
+ require "rubygems"
3
+ require "activerecord"
4
+ require File.dirname(__FILE__) + '/libs/acts_as_tree'
5
+ require File.dirname(__FILE__) + '/libs/rexml_fix'
6
+ require File.dirname(__FILE__) + '/../lib/searchgasm'
7
+
8
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
9
+
10
+ class Account < ActiveRecord::Base
11
+ has_many :users, :dependent => :destroy
12
+ has_many :orders, :through => :users
13
+ end
14
+
15
+ class User < ActiveRecord::Base
16
+ acts_as_tree
17
+ belongs_to :account
18
+ has_many :orders, :dependent => :destroy
19
+ end
20
+
21
+ class Order < ActiveRecord::Base
22
+ belongs_to :user
23
+ end
24
+
25
+ class Test::Unit::TestCase
26
+ def self.fixtures(*fixtures)
27
+ @fixtures ||= []
28
+ @fixtures += [fixtures].flatten
29
+ end
30
+
31
+ def setup_db
32
+ ActiveRecord::Schema.define(:version => 1) do
33
+ create_table :accounts do |t|
34
+ t.datetime :created_at
35
+ t.datetime :updated_at
36
+ t.string :name
37
+ t.boolean :active
38
+ end
39
+
40
+ create_table :users do |t|
41
+ t.datetime :created_at
42
+ t.datetime :updated_at
43
+ t.integer :account_id
44
+ t.integer :parent_id
45
+ t.string :first_name
46
+ t.string :last_name
47
+ t.boolean :active
48
+ t.text :bio
49
+ end
50
+
51
+ create_table :orders do |t|
52
+ t.datetime :created_at
53
+ t.datetime :updated_at
54
+ t.integer :user_id
55
+ t.float :total
56
+ t.text :description
57
+ t.binary :receipt
58
+ end
59
+ end
60
+ end
61
+
62
+ def load_fixtures
63
+ self.class.fixtures.each do |fixture|
64
+ records = YAML.load(File.read(File.dirname(__FILE__) + "/fixtures/#{fixture.to_s}.yml"))
65
+ records.each do |name, attributes|
66
+ record = fixture.to_s.singularize.classify.constantize.new
67
+ attributes.each { |k, v| record.send("#{k}=", v) }
68
+ record.save!
69
+ end
70
+ end
71
+ end
72
+
73
+ def teardown_db
74
+ ActiveRecord::Base.connection.tables.each do |table|
75
+ ActiveRecord::Base.connection.drop_table(table)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,116 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestSearchgasmBase < Test::Unit::TestCase
4
+ fixtures :accounts, :users, :orders
5
+
6
+ def setup
7
+ setup_db
8
+ load_fixtures
9
+ end
10
+
11
+ def teardown
12
+ teardown_db
13
+ end
14
+
15
+ def test_initialize
16
+ search = BinaryLogic::Searchgasm::Search::Base.new(Account, :conditions => {:name_like => "binary"}, :page => 2, :limit => 10, :readonly => true)
17
+ assert_equal Account, search.klass
18
+ assert_equal "binary", search.conditions.name_like
19
+ assert_equal 2, search.page
20
+ assert_equal 10, search.limit
21
+ assert_equal true, search.readonly
22
+ end
23
+
24
+ def test_setting_first_level_options
25
+ search = BinaryLogic::Searchgasm::Search::Base.new(Account)
26
+
27
+ search.include = :users
28
+ assert_equal :users, search.include
29
+
30
+ search.joins = "test"
31
+ assert_equal "test", search.joins
32
+
33
+ search.page = 5
34
+ assert_equal 1, search.page # haven't set a limit yet
35
+ assert_equal nil, search.offset
36
+
37
+ search.limit = 20
38
+ assert_equal search.limit, 20
39
+ assert_equal search.per_page, 20
40
+ assert_equal search.page, 5
41
+ assert_equal search.offset, 100
42
+
43
+ search.offset = 50
44
+ assert_equal search.offset, 50
45
+ assert_equal search.page, 3
46
+
47
+ search.per_page = 2
48
+ assert_equal search.per_page, 2
49
+ assert_equal search.limit, 2
50
+ assert_equal search.page, 25
51
+ assert_equal search.offset, 50
52
+
53
+ search.order = "name ASC"
54
+ assert_equal search.order, "name ASC"
55
+
56
+ search.select = "name"
57
+ assert_equal search.select, "name"
58
+
59
+ search.readonly = true
60
+ assert_equal search.readonly, true
61
+
62
+ search.group = "name"
63
+ assert_equal search.group, "name"
64
+
65
+ search.from = "accounts"
66
+ assert_equal search.from, "accounts"
67
+
68
+ search.lock = true
69
+ assert_equal search.lock, true
70
+ end
71
+
72
+ def test_conditions
73
+ search = BinaryLogic::Searchgasm::Search::Base.new(Account)
74
+ assert_kind_of BinaryLogic::Searchgasm::Search::Conditions, search.conditions
75
+ assert_equal search.conditions.klass, Account
76
+
77
+ search.conditions = {:name_like => "Binary"}
78
+ assert_kind_of BinaryLogic::Searchgasm::Search::Conditions, search.conditions
79
+ end
80
+
81
+ def test_sanitize
82
+ search = BinaryLogic::Searchgasm::Search::Base.new(Account)
83
+ search.per_page = 2
84
+ search.conditions.name_like = "Binary"
85
+ search.conditions.users.id_greater_than = 2
86
+ search.page = 3
87
+ search.readonly = true
88
+ assert_equal search.sanitize, {:include => :users, :offset => 6, :readonly => true, :conditions => ["(\"accounts\".\"name\" LIKE ?) AND (\"users\".\"id\" > ?)", "%Binary%", 2], :limit => 2 }
89
+ end
90
+
91
+ def test_searching
92
+ search = BinaryLogic::Searchgasm::Search::Base.new(Account)
93
+ search.conditions.name_like = "Binary"
94
+ assert_equal search.all, [Account.find(1), Account.find(3)]
95
+ assert_equal search.find(:all), [Account.find(1), Account.find(3)]
96
+ assert_equal search.first, Account.find(1)
97
+ assert_equal search.find(:first), Account.find(1)
98
+
99
+ search.per_page = 20
100
+ search.page = 2
101
+
102
+ assert_equal search.all, []
103
+ assert_equal search.find(:all), []
104
+ assert_equal search.first, nil
105
+ assert_equal search.find(:first), nil
106
+
107
+ search.per_page = 0
108
+ search.page = nil
109
+ search.conditions.users.first_name_contains = "Ben"
110
+ search.conditions.users.orders.description_keywords = "products, &*ap#ple $%^&*"
111
+ assert_equal search.all, [Account.find(1)]
112
+ assert_equal search.find(:all), [Account.find(1)]
113
+ assert_equal search.first, Account.find(1)
114
+ assert_equal search.find(:first), Account.find(1)
115
+ end
116
+ end