ransack 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.
Files changed (51) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +11 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +5 -0
  5. data/Rakefile +19 -0
  6. data/lib/ransack.rb +24 -0
  7. data/lib/ransack/adapters/active_record.rb +2 -0
  8. data/lib/ransack/adapters/active_record/base.rb +17 -0
  9. data/lib/ransack/adapters/active_record/context.rb +153 -0
  10. data/lib/ransack/configuration.rb +39 -0
  11. data/lib/ransack/constants.rb +23 -0
  12. data/lib/ransack/context.rb +152 -0
  13. data/lib/ransack/helpers.rb +2 -0
  14. data/lib/ransack/helpers/form_builder.rb +172 -0
  15. data/lib/ransack/helpers/form_helper.rb +27 -0
  16. data/lib/ransack/locale/en.yml +67 -0
  17. data/lib/ransack/naming.rb +53 -0
  18. data/lib/ransack/nodes.rb +7 -0
  19. data/lib/ransack/nodes/and.rb +8 -0
  20. data/lib/ransack/nodes/attribute.rb +36 -0
  21. data/lib/ransack/nodes/condition.rb +209 -0
  22. data/lib/ransack/nodes/grouping.rb +207 -0
  23. data/lib/ransack/nodes/node.rb +34 -0
  24. data/lib/ransack/nodes/or.rb +8 -0
  25. data/lib/ransack/nodes/sort.rb +39 -0
  26. data/lib/ransack/nodes/value.rb +120 -0
  27. data/lib/ransack/predicate.rb +57 -0
  28. data/lib/ransack/search.rb +114 -0
  29. data/lib/ransack/translate.rb +92 -0
  30. data/lib/ransack/version.rb +3 -0
  31. data/ransack.gemspec +29 -0
  32. data/spec/blueprints/articles.rb +5 -0
  33. data/spec/blueprints/comments.rb +5 -0
  34. data/spec/blueprints/notes.rb +3 -0
  35. data/spec/blueprints/people.rb +4 -0
  36. data/spec/blueprints/tags.rb +3 -0
  37. data/spec/console.rb +22 -0
  38. data/spec/helpers/ransack_helper.rb +2 -0
  39. data/spec/playground.rb +37 -0
  40. data/spec/ransack/adapters/active_record/base_spec.rb +30 -0
  41. data/spec/ransack/adapters/active_record/context_spec.rb +29 -0
  42. data/spec/ransack/configuration_spec.rb +11 -0
  43. data/spec/ransack/helpers/form_builder_spec.rb +39 -0
  44. data/spec/ransack/nodes/compound_condition_spec.rb +0 -0
  45. data/spec/ransack/nodes/condition_spec.rb +0 -0
  46. data/spec/ransack/nodes/grouping_spec.rb +13 -0
  47. data/spec/ransack/predicate_spec.rb +25 -0
  48. data/spec/ransack/search_spec.rb +182 -0
  49. data/spec/spec_helper.rb +28 -0
  50. data/spec/support/schema.rb +102 -0
  51. metadata +200 -0
File without changes
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ module Ransack
4
+ module Nodes
5
+ describe Grouping do
6
+ before do
7
+ @g = 1
8
+ end
9
+
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ module Ransack
4
+ describe Predicate do
5
+
6
+ before do
7
+ @s = Search.new(Person)
8
+ end
9
+
10
+ describe 'cont' do
11
+ it 'generates a LIKE query with value surrounded by %' do
12
+ @s.name_cont = 'ric'
13
+ @s.result.to_sql.should match /"people"."name" LIKE '%ric%'/
14
+ end
15
+ end
16
+
17
+ describe 'not_cont' do
18
+ it 'generates a NOT LIKE query with value surrounded by %' do
19
+ @s.name_not_cont = 'ric'
20
+ @s.result.to_sql.should match /"people"."name" NOT LIKE '%ric%'/
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+
3
+ module Ransack
4
+ describe Search do
5
+
6
+ describe '#build' do
7
+ it 'creates Conditions for top-level attributes' do
8
+ search = Search.new(Person, :name_eq => 'Ernie')
9
+ condition = search.base[:name_eq]
10
+ condition.should be_a Nodes::Condition
11
+ condition.predicate.name.should eq 'eq'
12
+ condition.attributes.first.name.should eq 'name'
13
+ condition.value.should eq 'Ernie'
14
+ end
15
+
16
+ it 'creates Conditions for association attributes' do
17
+ search = Search.new(Person, :children_name_eq => 'Ernie')
18
+ condition = search.base[:children_name_eq]
19
+ condition.should be_a Nodes::Condition
20
+ condition.predicate.name.should eq 'eq'
21
+ condition.attributes.first.name.should eq 'children_name'
22
+ condition.value.should eq 'Ernie'
23
+ end
24
+
25
+ it 'discards empty conditions' do
26
+ search = Search.new(Person, :children_name_eq => '')
27
+ condition = search.base[:children_name_eq]
28
+ condition.should be_nil
29
+ end
30
+
31
+ it 'accepts arrays of groupings' do
32
+ search = Search.new(Person,
33
+ :o => [
34
+ {:name_eq => 'Ernie', :children_name_eq => 'Ernie'},
35
+ {:name_eq => 'Bert', :children_name_eq => 'Bert'},
36
+ ]
37
+ )
38
+ ors = search.ors
39
+ ors.should have(2).items
40
+ or1, or2 = ors
41
+ or1.should be_a Nodes::Or
42
+ or2.should be_a Nodes::Or
43
+ end
44
+
45
+ it 'accepts "attributes" hashes for groupings' do
46
+ search = Search.new(Person,
47
+ :o => {
48
+ '0' => {:name_eq => 'Ernie', :children_name_eq => 'Ernie'},
49
+ '1' => {:name_eq => 'Bert', :children_name_eq => 'Bert'},
50
+ }
51
+ )
52
+ ors = search.ors
53
+ ors.should have(2).items
54
+ or1, or2 = ors
55
+ or1.should be_a Nodes::Or
56
+ or2.should be_a Nodes::Or
57
+ end
58
+
59
+ it 'accepts "attributes" hashes for conditions' do
60
+ search = Search.new(Person,
61
+ :c => {
62
+ '0' => {:a => ['name'], :p => 'eq', :v => ['Ernie']},
63
+ '1' => {:a => ['children_name', 'parent_name'], :p => 'eq', :v => ['Ernie'], :m => 'or'}
64
+ }
65
+ )
66
+ conditions = search.base.conditions
67
+ conditions.should have(2).items
68
+ conditions.map {|c| c.class}.should eq [Nodes::Condition, Nodes::Condition]
69
+ end
70
+ end
71
+
72
+ describe '#result' do
73
+ it 'evaluates conditions contextually' do
74
+ search = Search.new(Person, :children_name_eq => 'Ernie')
75
+ search.result.should be_an ActiveRecord::Relation
76
+ where = search.result.where_values.first
77
+ where.to_sql.should match /"children_people"\."name" = 'Ernie'/
78
+ end
79
+
80
+ it 'evaluates compound conditions contextually' do
81
+ search = Search.new(Person, :children_name_or_name_eq => 'Ernie')
82
+ search.result.should be_an ActiveRecord::Relation
83
+ where = search.result.where_values.first
84
+ where.to_sql.should match /"children_people"\."name" = 'Ernie' OR "people"\."name" = 'Ernie'/
85
+ end
86
+
87
+ it 'evaluates nested conditions' do
88
+ search = Search.new(Person, :children_name_eq => 'Ernie',
89
+ :o => [{
90
+ :name_eq => 'Ernie',
91
+ :children_children_name_eq => 'Ernie'
92
+ }]
93
+ )
94
+ search.result.should be_an ActiveRecord::Relation
95
+ where = search.result.where_values.first
96
+ where.to_sql.should match /\("children_people"."name" = 'Ernie' AND \("people"."name" = 'Ernie' OR "children_people_2"."name" = 'Ernie'\)\)/
97
+ end
98
+
99
+ it 'evaluates arrays of groupings' do
100
+ search = Search.new(Person,
101
+ :o => [
102
+ {:name_eq => 'Ernie', :children_name_eq => 'Ernie'},
103
+ {:name_eq => 'Bert', :children_name_eq => 'Bert'},
104
+ ]
105
+ )
106
+ search.result.should be_an ActiveRecord::Relation
107
+ where = search.result.where_values.first
108
+ where.to_sql.should match /\(\("people"."name" = 'Ernie' OR "children_people"."name" = 'Ernie'\) AND \("people"."name" = 'Bert' OR "children_people"."name" = 'Bert'\)\)/
109
+ end
110
+ end
111
+
112
+ describe '#sorts=' do
113
+ before do
114
+ @s = Search.new(Person)
115
+ end
116
+
117
+ it 'creates sorts based on a single attribute/direction' do
118
+ @s.sorts = 'id desc'
119
+ @s.sorts.should have(1).item
120
+ sort = @s.sorts.first
121
+ sort.should be_a Nodes::Sort
122
+ sort.name.should eq 'id'
123
+ sort.dir.should eq 'desc'
124
+ end
125
+
126
+ it 'creates sorts based on multiple attributes/directions in array format' do
127
+ @s.sorts = ['id desc', 'name asc']
128
+ @s.sorts.should have(2).items
129
+ sort1, sort2 = @s.sorts
130
+ sort1.should be_a Nodes::Sort
131
+ sort1.name.should eq 'id'
132
+ sort1.dir.should eq 'desc'
133
+ sort2.should be_a Nodes::Sort
134
+ sort2.name.should eq 'name'
135
+ sort2.dir.should eq 'asc'
136
+ end
137
+
138
+ it 'creates sorts based on multiple attributes/directions in hash format' do
139
+ @s.sorts = {
140
+ '0' => {
141
+ :name => 'id',
142
+ :dir => 'desc'
143
+ },
144
+ '1' => {
145
+ :name => 'name',
146
+ :dir => 'asc'
147
+ }
148
+ }
149
+ @s.sorts.should have(2).items
150
+ sort1, sort2 = @s.sorts
151
+ sort1.should be_a Nodes::Sort
152
+ sort1.name.should eq 'id'
153
+ sort1.dir.should eq 'desc'
154
+ sort2.should be_a Nodes::Sort
155
+ sort2.name.should eq 'name'
156
+ sort2.dir.should eq 'asc'
157
+ end
158
+ end
159
+
160
+ describe '#method_missing' do
161
+ before do
162
+ @s = Search.new(Person)
163
+ end
164
+
165
+ it 'raises NoMethodError when sent an invalid attribute' do
166
+ expect {@s.blah}.to raise_error NoMethodError
167
+ end
168
+
169
+ it 'sets condition attributes when sent valid attributes' do
170
+ @s.name_eq = 'Ernie'
171
+ @s.name_eq.should eq 'Ernie'
172
+ end
173
+
174
+ it 'allows chaining to access nested conditions' do
175
+ @s.ors = [{:name_eq => 'Ernie', :children_name_eq => 'Ernie'}]
176
+ @s.ors.first.name_eq.should eq 'Ernie'
177
+ @s.ors.first.children_name_eq.should eq 'Ernie'
178
+ end
179
+ end
180
+
181
+ end
182
+ end
@@ -0,0 +1,28 @@
1
+ require 'machinist/active_record'
2
+ require 'sham'
3
+ require 'faker'
4
+
5
+ Time.zone = 'Eastern Time (US & Canada)'
6
+
7
+ Dir[File.expand_path('../{helpers,support,blueprints}/*.rb', __FILE__)].each do |f|
8
+ require f
9
+ end
10
+
11
+ Sham.define do
12
+ name { Faker::Name.name }
13
+ title { Faker::Lorem.sentence }
14
+ body { Faker::Lorem.paragraph }
15
+ salary {|index| 30000 + (index * 1000)}
16
+ tag_name { Faker::Lorem.words(3).join(' ') }
17
+ note { Faker::Lorem.words(7).join(' ') }
18
+ end
19
+
20
+ RSpec.configure do |config|
21
+ config.before(:suite) { Schema.create }
22
+ config.before(:all) { Sham.reset(:before_all) }
23
+ config.before(:each) { Sham.reset(:before_each) }
24
+
25
+ config.include RansackHelper
26
+ end
27
+
28
+ require 'ransack'
@@ -0,0 +1,102 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Base.establish_connection(
4
+ :adapter => 'sqlite3',
5
+ :database => ':memory:'
6
+ )
7
+
8
+ class Person < ActiveRecord::Base
9
+ belongs_to :parent, :class_name => 'Person', :foreign_key => :parent_id
10
+ has_many :children, :class_name => 'Person', :foreign_key => :parent_id
11
+ has_many :articles
12
+ has_many :comments
13
+ has_many :authored_article_comments, :through => :articles,
14
+ :class_name => 'Comment', :foreign_key => :person_id
15
+ has_many :notes, :as => :notable
16
+ end
17
+
18
+ class Article < ActiveRecord::Base
19
+ belongs_to :person
20
+ has_many :comments
21
+ has_and_belongs_to_many :tags
22
+ has_many :notes, :as => :notable
23
+ end
24
+
25
+ class Comment < ActiveRecord::Base
26
+ belongs_to :article
27
+ belongs_to :person
28
+ end
29
+
30
+ class Tag < ActiveRecord::Base
31
+ has_and_belongs_to_many :articles
32
+ end
33
+
34
+ class Note < ActiveRecord::Base
35
+ belongs_to :notable, :polymorphic => true
36
+ end
37
+
38
+ module Schema
39
+ def self.create
40
+ ActiveRecord::Base.silence do
41
+ ActiveRecord::Migration.verbose = false
42
+
43
+ ActiveRecord::Schema.define do
44
+ create_table :people, :force => true do |t|
45
+ t.integer :parent_id
46
+ t.string :name
47
+ t.integer :salary
48
+ t.timestamps
49
+ end
50
+
51
+ create_table :articles, :force => true do |t|
52
+ t.integer :person_id
53
+ t.string :title
54
+ t.text :body
55
+ end
56
+
57
+ create_table :comments, :force => true do |t|
58
+ t.integer :article_id
59
+ t.integer :person_id
60
+ t.text :body
61
+ end
62
+
63
+ create_table :tags, :force => true do |t|
64
+ t.string :name
65
+ end
66
+
67
+ create_table :articles_tags, :force => true, :id => false do |t|
68
+ t.integer :article_id
69
+ t.integer :tag_id
70
+ end
71
+
72
+ create_table :notes, :force => true do |t|
73
+ t.integer :notable_id
74
+ t.string :notable_type
75
+ t.string :note
76
+ end
77
+
78
+ end
79
+ end
80
+
81
+ 10.times do
82
+ person = Person.make
83
+ Note.make(:notable => person)
84
+ 3.times do
85
+ article = Article.make(:person => person)
86
+ 3.times do
87
+ article.tags = [Tag.make, Tag.make, Tag.make]
88
+ end
89
+ Note.make(:notable => article)
90
+ 10.times do
91
+ Comment.make(:article => article)
92
+ end
93
+ end
94
+ 2.times do
95
+ Comment.make(:person => person)
96
+ end
97
+ end
98
+
99
+ Comment.make(:body => 'First post!', :article => Article.make(:title => 'Hello, world!'))
100
+
101
+ end
102
+ end
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ransack
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Ernie Miller
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-03-30 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: activerecord
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 3.1.0.alpha
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 3.1.0.alpha
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: actionpack
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 3.1.0.alpha
47
+ type: :runtime
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ version: 2.5.0
58
+ type: :development
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: machinist
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.0.6
69
+ type: :development
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: faker
73
+ prerelease: false
74
+ requirement: &id006 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ~>
78
+ - !ruby/object:Gem::Version
79
+ version: 0.9.5
80
+ type: :development
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: sqlite3
84
+ prerelease: false
85
+ requirement: &id007 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ version: 1.3.3
91
+ type: :development
92
+ version_requirements: *id007
93
+ description: Not yet ready for public consumption.
94
+ email:
95
+ - ernie@metautonomo.us
96
+ executables: []
97
+
98
+ extensions: []
99
+
100
+ extra_rdoc_files: []
101
+
102
+ files:
103
+ - .gitignore
104
+ - Gemfile
105
+ - LICENSE
106
+ - README.rdoc
107
+ - Rakefile
108
+ - lib/ransack.rb
109
+ - lib/ransack/adapters/active_record.rb
110
+ - lib/ransack/adapters/active_record/base.rb
111
+ - lib/ransack/adapters/active_record/context.rb
112
+ - lib/ransack/configuration.rb
113
+ - lib/ransack/constants.rb
114
+ - lib/ransack/context.rb
115
+ - lib/ransack/helpers.rb
116
+ - lib/ransack/helpers/form_builder.rb
117
+ - lib/ransack/helpers/form_helper.rb
118
+ - lib/ransack/locale/en.yml
119
+ - lib/ransack/naming.rb
120
+ - lib/ransack/nodes.rb
121
+ - lib/ransack/nodes/and.rb
122
+ - lib/ransack/nodes/attribute.rb
123
+ - lib/ransack/nodes/condition.rb
124
+ - lib/ransack/nodes/grouping.rb
125
+ - lib/ransack/nodes/node.rb
126
+ - lib/ransack/nodes/or.rb
127
+ - lib/ransack/nodes/sort.rb
128
+ - lib/ransack/nodes/value.rb
129
+ - lib/ransack/predicate.rb
130
+ - lib/ransack/search.rb
131
+ - lib/ransack/translate.rb
132
+ - lib/ransack/version.rb
133
+ - ransack.gemspec
134
+ - spec/blueprints/articles.rb
135
+ - spec/blueprints/comments.rb
136
+ - spec/blueprints/notes.rb
137
+ - spec/blueprints/people.rb
138
+ - spec/blueprints/tags.rb
139
+ - spec/console.rb
140
+ - spec/helpers/ransack_helper.rb
141
+ - spec/playground.rb
142
+ - spec/ransack/adapters/active_record/base_spec.rb
143
+ - spec/ransack/adapters/active_record/context_spec.rb
144
+ - spec/ransack/configuration_spec.rb
145
+ - spec/ransack/helpers/form_builder_spec.rb
146
+ - spec/ransack/nodes/compound_condition_spec.rb
147
+ - spec/ransack/nodes/condition_spec.rb
148
+ - spec/ransack/nodes/grouping_spec.rb
149
+ - spec/ransack/predicate_spec.rb
150
+ - spec/ransack/search_spec.rb
151
+ - spec/spec_helper.rb
152
+ - spec/support/schema.rb
153
+ has_rdoc: true
154
+ homepage: http://metautonomo.us/projects/ransack
155
+ licenses: []
156
+
157
+ post_install_message:
158
+ rdoc_options: []
159
+
160
+ require_paths:
161
+ - lib
162
+ required_ruby_version: !ruby/object:Gem::Requirement
163
+ none: false
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: "0"
168
+ required_rubygems_version: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: "0"
174
+ requirements: []
175
+
176
+ rubyforge_project: ransack
177
+ rubygems_version: 1.5.3
178
+ signing_key:
179
+ specification_version: 3
180
+ summary: Object-based searching. Like MetaSearch, but this time, with a better name.
181
+ test_files:
182
+ - spec/blueprints/articles.rb
183
+ - spec/blueprints/comments.rb
184
+ - spec/blueprints/notes.rb
185
+ - spec/blueprints/people.rb
186
+ - spec/blueprints/tags.rb
187
+ - spec/console.rb
188
+ - spec/helpers/ransack_helper.rb
189
+ - spec/playground.rb
190
+ - spec/ransack/adapters/active_record/base_spec.rb
191
+ - spec/ransack/adapters/active_record/context_spec.rb
192
+ - spec/ransack/configuration_spec.rb
193
+ - spec/ransack/helpers/form_builder_spec.rb
194
+ - spec/ransack/nodes/compound_condition_spec.rb
195
+ - spec/ransack/nodes/condition_spec.rb
196
+ - spec/ransack/nodes/grouping_spec.rb
197
+ - spec/ransack/predicate_spec.rb
198
+ - spec/ransack/search_spec.rb
199
+ - spec/spec_helper.rb
200
+ - spec/support/schema.rb