collection_extensions 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,10 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.8.7
4
3
  - 1.9.2
5
4
  - 1.9.3
6
- - jruby-18mode
7
5
  - jruby-19mode
8
- - rbx-18mode
9
6
  - rbx-19mode
10
- - ree
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in collection_extensions.gemspec
4
4
  gemspec
5
5
 
6
+ gem 'activerecord', '~> 3.2'
7
+
6
8
  group :test do
7
9
  gem "rake", "~> 0.9.2"
8
10
  gem 'rspec', '~> 2.11.0'
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # CollectionExtensions
2
2
 
3
3
  Sometimes an operation just doesn't fit well into a scope, but you don't want to lose your declarative code style
4
- by operating on all the objects individually. This gem adds a few lines of code to make it easier to add methods to collections of objects.
4
+ by operating on all the objects individually. This gem adds a few lines of code to make it easier to add methods
5
+ to collections of ActiveRecord objects.
5
6
 
6
7
  <img src="https://secure.travis-ci.org/arches/collection_extensions.png" />
7
8
 
@@ -9,44 +10,56 @@ by operating on all the objects individually. This gem adds a few lines of code
9
10
 
10
11
  Add this line to your application's Gemfile:
11
12
 
12
- gem 'collection_extensions'
13
+ ```ruby
14
+ gem 'collection_extensions'
15
+ ```
13
16
 
14
17
  And then execute:
15
18
 
16
- $ bundle
19
+ ```bash
20
+ $ bundle
21
+ ```
17
22
 
18
23
  Or install it yourself as:
19
24
 
20
- $ gem install collection_extensions
25
+ ```bash
26
+ $ gem install collection_extensions
27
+ ```
21
28
 
22
29
  ## Usage
23
30
 
24
- Include the module in your model and specify what collections you want to extend:
31
+ A collections of records will be extended based on the naming convention `%sCollectionExtensions`, where the `%s` substitution
32
+ is the camel-cased name of the class. For example, collections of User objects will be extended with the methods in the
33
+ `UserCollectionExtensions` model and collections of BlogPost objects will be extended with the methods in the `BlogPostCollectionExtensions`
34
+ module.
25
35
 
26
- class User < ActiveRecord::Base
27
- include CollectionExtensions
28
- has_many :orders, :preferences
29
- extend_collections :orders, :preferences
30
-
31
- # the original unextended collection is still available, aliased as orig_* (eg, orig_orders or orig_preferences)
32
- end
33
-
34
- This will use the modules OrdersCollectionExtensions and PreferencesCollectionExtensions to extend those associations
35
- whenever you use them. For example:
36
+ ```ruby
37
+ module BlogPostCollectionExtensions
36
38
 
37
- module OrdersCollectionExtensions
38
- def for_product_id(product_id)
39
- # 'self' is the array of orders
40
- select {|o| o.line_items.collect(&:product_id).include? product_id}
39
+ # hash key is user ID, hash value is the number of comments they've posted on this set of blog posts
40
+ def comments_per_user
41
+ comment_counts = {}
42
+
43
+ # 'self' is the array of blog posts
44
+ each do |blog_post|
45
+ blog_post.comments.each do |comment|
46
+ comment_counts[comment.user_id] ||= 0
47
+ comment_counts[comment.user_id] += 1
41
48
  end
42
49
  end
43
50
 
44
- > User.find(1).orders.for_product_id(2)
51
+ comment_counts
52
+ end
53
+ end
54
+ ```
45
55
 
46
- If you want a different naming convention, set the config variable using `%s` string substitution:
56
+ ### Naming Convention
47
57
 
48
- CollectionExtensions::Config.naming_convention = "MethodsForCollectionsOf%s"
58
+ If you want a different naming convention, set the config variable using `%s` string substitution:
49
59
 
60
+ ```ruby
61
+ CollectionExtensions::Config.naming_convention = "MethodsForCollectionsOf%s"
62
+ ```
50
63
 
51
64
  ## Contributing
52
65
 
@@ -1,25 +1,32 @@
1
1
  require "collection_extensions/version"
2
2
  require "collection_extensions/cattr"
3
3
  require "collection_extensions/config"
4
+ require "active_record"
4
5
 
5
- module CollectionExtensions
6
+ class ActiveRecord::Relation
7
+ alias :orig_to_a :to_a
8
+ alias :orig_method_missing :method_missing
6
9
 
7
- def self.included(base)
8
- base.extend ClassMethods
9
- end
10
+ def to_a
11
+ records = orig_to_a
12
+
13
+ records.extend extension_module if extension_module
10
14
 
11
- module ClassMethods
12
- def extend_collections(*associations)
13
- Array(associations).each do |association|
14
- alias_method "orig_#{association}", association
15
+ records
16
+ end
15
17
 
16
- define_method association do
17
- upper_camel = association.to_s.split("_").collect{|piece| piece.capitalize}.join
18
- extender = Object.const_get(CollectionExtensions::Config.naming_convention % upper_camel)
19
- send("orig_#{association}").extend(extender)
20
- end
21
- end
18
+ def extension_module
19
+ extension_klass = CollectionExtensions::Config.naming_convention % @klass.to_s
20
+ if Object.constants.include? extension_klass.to_sym
21
+ Object.const_get(extension_klass)
22
22
  end
23
23
  end
24
24
 
25
+ def method_missing(method, *args, &block)
26
+ if extension_module and extension_module.method_defined? method
27
+ to_a.send(method, *args, &block)
28
+ else
29
+ orig_method_missing(method, *args, &block)
30
+ end
31
+ end
25
32
  end
@@ -1,3 +1,3 @@
1
1
  module CollectionExtensions
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -1,69 +1,67 @@
1
+ require 'active_record'
1
2
  require 'collection_extensions'
2
3
 
3
- module ExamplesCollectionExtensions
4
- def operate_on_all_examples
5
- "operate_on_all_examples"
4
+ module UserCollectionExtensions
5
+ def utest
6
+ "ufoo"
6
7
  end
7
8
  end
8
9
 
9
- module FoobarsCollectionExtensions
10
- def operate_on_all_foobars
11
- "operate_on_all_foobars"
12
- end
10
+ module ExtensionMethodsForUserCollections
13
11
  end
14
12
 
15
- module MethodsForCollectionsOfExamples
16
- def operate_on_all_examples
17
- "from a module with a different naming convention"
18
- end
19
- end
20
-
21
- class CollectionTester
22
- include CollectionExtensions
23
-
24
- def examples
25
- "original examples method"
13
+ describe "#extension_class" do
14
+ context "when the extension module exists" do
15
+ it "returns the constant" do
16
+ r = ActiveRecord::Relation.new :User, :users
17
+ r.extension_module.should == UserCollectionExtensions
18
+ end
26
19
  end
27
20
 
28
- def foobars
29
- "original foobars method"
21
+ context "when the extension module doesn't exist" do
22
+ it "returns nil" do
23
+ r = ActiveRecord::Relation.new :Order, :orders
24
+ r.extension_module.should be_nil
25
+ end
30
26
  end
31
27
 
32
- extend_collections :examples, :foobars
33
- end
34
-
35
- describe CollectionExtensions do
36
- let(:ct) { CollectionTester.new }
28
+ context "when the naming convention has been changed" do
29
+ before { CollectionExtensions::Config.naming_convention = "ExtensionMethodsForUserCollections" }
30
+ after { CollectionExtensions::Config.naming_convention = CollectionExtensions::Config::DEFAULT_NAMING_CONVENTION }
37
31
 
38
- describe "#extend_collections" do
39
- it "aliases the examples" do
40
- ct.orig_examples.should == "original examples method"
41
- ct.examples.should be_a ExamplesCollectionExtensions
42
- ct.examples.operate_on_all_examples.should == "operate_on_all_examples"
43
- end
44
-
45
- it "aliases the foobars" do
46
- ct.orig_foobars.should == "original foobars method"
47
- ct.foobars.should be_a FoobarsCollectionExtensions
48
- ct.foobars.operate_on_all_foobars.should == "operate_on_all_foobars"
32
+ it "uses the proper convention to return the constant" do
33
+ r = ActiveRecord::Relation.new :User, :users
34
+ r.extension_module.should == ExtensionMethodsForUserCollections
49
35
  end
50
36
  end
51
37
  end
52
38
 
53
- describe "changing the naming convention" do
54
- let(:ct) { CollectionTester.new }
55
-
56
- before do
57
- CollectionTester::Config.naming_convention = "MethodsForCollectionsOf%s"
39
+ describe "calling methods on the array" do
40
+ it "pulls extension methods from the module" do
41
+ r = ActiveRecord::Relation.new :User, :users
42
+ r.stub(orig_to_a: [])
43
+ r.to_a.utest.should == "ufoo"
58
44
  end
45
+ end
59
46
 
60
- it "extends the association with the proper module" do
61
- ct.orig_examples.should == "original examples method"
62
- ct.examples.should be_a MethodsForCollectionsOfExamples
63
- ct.examples.operate_on_all_examples.should == "from a module with a different naming convention"
47
+ describe "calling methods on the relation" do
48
+ it "pulls extension methods from the module" do
49
+ r = ActiveRecord::Relation.new :User, :users
50
+ r.stub(orig_to_a: [])
51
+ r.utest.should == "ufoo"
64
52
  end
65
- end
66
53
 
67
- describe "" do
54
+ it "lets non-extension methods pass through" do
55
+ r = ActiveRecord::Relation.new :User, :users
56
+ r.stub(orig_to_a: ['first'])
57
+ r.first.should == 'first'
58
+ end
68
59
 
60
+ context "when the extension module doesn't exist" do
61
+ it "lets methods pass through" do
62
+ r = ActiveRecord::Relation.new :Order, :orders
63
+ r.stub(orig_to_a: ['first'])
64
+ r.first.should == 'first'
65
+ end
66
+ end
69
67
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: collection_extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-04 00:00:00.000000000 Z
12
+ date: 2012-09-05 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description: Lightweight framework for adding methods to groups of ActiveRecord objects
15
15
  email: