in_place_relation 0.1.0 → 0.1.1

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/.hgignore ADDED
@@ -0,0 +1,2 @@
1
+ syntax: glob
2
+ *swp
data/README ADDED
@@ -0,0 +1,19 @@
1
+ # This module provides an in-place wrapper for ActiveRecord::Relation.
2
+ #
3
+ # So instead of doing this:
4
+ # rel = SomeModel.where( ... )
5
+ # rel = rel.joins(...).where(...) if x
6
+ # rel = rel.select(...) unless y
7
+ # rel = rel.merge( another_rel )
8
+ # rel.all
9
+ #
10
+ # you can do this:
11
+ # rel = SomeModel.where( ... ).in_place
12
+ # rel.joins(...).where(...) if x
13
+ # rel.select(...) unless y
14
+ # rel.merge( another_rel )
15
+ # rel.all
16
+ #
17
+ # All ActiveRecord::Relation methods are either wrapped and return wrapper
18
+ # itself or are passed directly to underlying relation object. In rare case you
19
+ # might want to access this relation object directly, use #relation method
data/Rakefile CHANGED
@@ -1 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ # Now I have no idea why this doesn't work without specifying the task explicitly
4
+ require "rake/testtask"
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList['test/*test.rb']
8
+ t.verbose = true
9
+ end
@@ -18,7 +18,6 @@ Gem::Specification.new do |s|
18
18
  s.executables = `hg manifest | grep ^bin`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- # specify any dependencies here; for example:
22
- # s.add_development_dependency "rspec"
21
+ s.add_development_dependency "activerecord-nulldb-adapter"
23
22
  s.add_runtime_dependency "activerecord", ">= 3"
24
23
  end
@@ -1,17 +1,5 @@
1
1
  require "in_place_relation/version"
2
2
 
3
- # This module provides an in-place wrapper for ActiveRecord::Relation. So
4
- # instead of doing this:
5
- # rel = SomeModel.where( ... )
6
- # rel = rel.joins().where() if x
7
- # rel = rel.select() unless y
8
- # rel.all
9
- #
10
- # you can do this
11
- # rel = SomeModel.where( ... ).in_place
12
- # rel.joins().where() if x
13
- # rel.select() unless y
14
- # rel.all
15
3
  #
16
4
  # and get original relation with:
17
5
  # rel.relation # ActiveRecord::Relation
@@ -20,17 +8,21 @@ module InPlaceRelation
20
8
  module Methods
21
9
 
22
10
  def in_place
23
- return Wrapper.new( self )
11
+ # To keep things unified we always want a Relation here even if initial
12
+ # object was a model class or an association
13
+ rel = self.is_a?( ActiveRecord::Relation ) ? self : self.scoped
14
+ return Wrapper.new( rel )
24
15
  end
25
16
  end
26
17
 
27
18
  class Wrapper
28
19
 
20
+ # Wrapped ActiveRecord::Relation object
29
21
  attr_reader :relation
30
22
 
31
23
  METHODS_TO_WRAP = ActiveRecord::Relation::ASSOCIATION_METHODS + ActiveRecord::Relation::MULTI_VALUE_METHODS + ActiveRecord::Relation::SINGLE_VALUE_METHODS + [:merge]
32
24
 
33
- METHODS_TO_WRAP.each do |meth|
25
+ METHODS_TO_WRAP.uniq.each do |meth|
34
26
  define_method( meth ) do |*args|
35
27
  @relation = @relation.send( meth, *args )
36
28
  return self
@@ -49,6 +41,10 @@ module InPlaceRelation
49
41
  @relation.send( name, *args, &block )
50
42
  end
51
43
 
44
+ def in_place
45
+ return self
46
+ end
47
+
52
48
  end
53
49
 
54
50
  end
@@ -1,3 +1,3 @@
1
1
  module InPlaceRelation
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -0,0 +1,118 @@
1
+ require 'active_record'
2
+ require 'test/unit'
3
+ require 'in_place_relation'
4
+
5
+ # Workaround for nulldb Rails 3.1 incompatibility
6
+ class Object
7
+
8
+ def returning( obj, &block )
9
+ obj.tap( &block )
10
+ end
11
+ end
12
+
13
+ class InPlaceRelationTest < Test::Unit::TestCase
14
+
15
+ ActiveRecord::Base.establish_connection :adapter => :nulldb
16
+
17
+ class Post < ActiveRecord::Base
18
+ has_many :comments
19
+ end
20
+
21
+ class Comment < ActiveRecord::Base
22
+ belongs_to :post
23
+ end
24
+
25
+ Post.connection.create_table "posts" do |t|
26
+ t.string :name
27
+ t.text :content
28
+ t.timestamps
29
+ end
30
+
31
+ Comment.connection.create_table "comments" do |t|
32
+ t.integer :post_id
33
+ t.string :title
34
+ t.text :content
35
+ t.timestamps
36
+ end
37
+
38
+ def test_on_class
39
+ rel = Post.in_place
40
+ oid = rel.object_id
41
+ rel.where( :id => 1 )
42
+ rel.joins( :comments )
43
+ rel.order( "id DESC" )
44
+ rel.limit( 20 )
45
+ rel.select( "DISTINCT posts.id" )
46
+ assert_equal oid, rel.object_id
47
+ assert_equal "posts.id = 1", rel.where_values.first.to_sql
48
+ #assert_equal "INNER JOIN comments ON comments.post_id = posts.id", rel.joins_values.first.to_sql
49
+ assert_equal "id DESC", rel.order_values.first
50
+ assert_equal 20, rel.limit_value
51
+ assert_equal "DISTINCT posts.id", rel.select_values.first
52
+ end
53
+
54
+ # This test doesn't work without database connection, probably passing schema
55
+ # to nulldb would suffice
56
+ def test_on_association
57
+ p = Post.create!( :id => 11 )
58
+ rel = p.comments.in_place
59
+ oid = rel.object_id
60
+ rel.where( :name => "NAME" )
61
+ rel.joins( :comments )
62
+ rel.order( "id DESC" )
63
+ rel.limit( 20 )
64
+ rel.select( "DISTINCT posts.id" )
65
+ assert_equal oid, rel.object_id
66
+ assert_equal "posts.id = 1", rel.where_sql
67
+ #assert_equal "INNER JOIN comments ON comments.post_id = posts.id", rel.joins_values.first.to_sql
68
+ assert_equal "id DESC", rel.order_values.first
69
+ assert_equal 20, rel.limit_value
70
+ assert_equal "DISTINCT posts.id", rel.select_values.first
71
+ end
72
+
73
+ def test_on_relation
74
+ rel = Post.where( :name => "some" ).in_place
75
+ oid = rel.object_id
76
+ rel.where( :id => 1 )
77
+ rel.joins( :comments )
78
+ rel.order( "id DESC" )
79
+ rel.limit( 20 )
80
+ rel.select( "DISTINCT posts.id" )
81
+ assert_equal oid, rel.object_id
82
+ assert_equal "WHERE posts.name = 'some' AND posts.id = 1", rel.where_sql
83
+ #assert_equal "INNER JOIN comments ON comments.post_id = posts.id", rel.joins_values.first.to_sql
84
+ assert_equal "id DESC", rel.order_values.first
85
+ assert_equal 20, rel.limit_value
86
+ assert_equal "DISTINCT posts.id", rel.select_values.first
87
+ end
88
+
89
+ def test_in_place_identity
90
+ rel = Comment.in_place
91
+ oid = rel.object_id
92
+ 10.times { rel = rel.in_place }
93
+ assert_equal oid, rel.object_id
94
+ end
95
+
96
+ def test_where_chaining
97
+ rel = Post.where( :id => 1 ).in_place
98
+ rel.where( :id => 2, :name => "adsf" ).where( :created_at => "2011-01-01 00:00:00" ).where( "content LIKE ?", "%content word%" )
99
+ assert_equal "WHERE posts.id = 1 AND posts.id = 2 AND posts.name = 'adsf' AND posts.created_at = '2011-01-01 00:00:00' AND (content LIKE '%content word%')", rel.where_sql
100
+ end
101
+
102
+ def test_relation_identity
103
+ rel = Comment.where( :title => 'fdsa' )
104
+ wrap = rel.in_place
105
+ assert_equal rel.object_id, wrap.relation.object_id
106
+ assert_equal rel.where_sql, wrap.relation.where_sql
107
+ end
108
+
109
+ def test_merge
110
+ rel = Comment.where( :title => 'fdsa' )
111
+ wrap = Comment.where( :post_id => 43 ).in_place
112
+ oid = wrap.object_id
113
+ wrap.merge( rel )
114
+ assert_equal oid, wrap.object_id
115
+ assert_equal "WHERE comments.post_id = 43 AND comments.title = 'fdsa'", wrap.where_sql
116
+ end
117
+
118
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: in_place_relation
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Marek Janukowicz/Starware
@@ -15,13 +15,27 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-11-28 00:00:00 +01:00
18
+ date: 2012-01-03 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: activerecord
22
+ name: activerecord-nulldb-adapter
23
23
  prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: activerecord
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
25
39
  none: false
26
40
  requirements:
27
41
  - - ">="
@@ -31,7 +45,7 @@ dependencies:
31
45
  - 3
32
46
  version: "3"
33
47
  type: :runtime
34
- version_requirements: *id001
48
+ version_requirements: *id002
35
49
  description: ActiveRecord::Relation wrapper that can be modified/combined in place
36
50
  email:
37
51
  - marek@janukowicz.net
@@ -42,11 +56,14 @@ extensions: []
42
56
  extra_rdoc_files: []
43
57
 
44
58
  files:
59
+ - .hgignore
45
60
  - Gemfile
61
+ - README
46
62
  - Rakefile
47
63
  - in_place_relation.gemspec
48
64
  - lib/in_place_relation.rb
49
65
  - lib/in_place_relation/version.rb
66
+ - test/in_place_relation_test.rb
50
67
  has_rdoc: true
51
68
  homepage: ""
52
69
  licenses: []
@@ -81,5 +98,5 @@ rubygems_version: 1.6.2
81
98
  signing_key:
82
99
  specification_version: 3
83
100
  summary: A relation that can be changed in place
84
- test_files: []
85
-
101
+ test_files:
102
+ - test/in_place_relation_test.rb