prim 0.0.3 → 0.0.4

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/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ LICENSE
2
+
3
+ The MIT License
4
+
5
+ Copyright (c) 2012 Piers Mainwaring and Orca Health, Inc.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
data/README.md CHANGED
@@ -32,9 +32,13 @@ end
32
32
 
33
33
  Great! Now let's say we've added a specific set of Languages. Our Users can now have new Language associations by simply creating a record in the `user_languages` mapping table, relating a User and a Language. But what if we want to know which of a User's Languages is their most important? Well, we could add a `sort_order` or `primary` column to the `user_languages` table, but then we'll need to write code to manage it all.
34
34
 
35
- Enter __Prim__.
35
+ Enter __Prim__. Add
36
36
 
37
- With __Prim__ we can just add a line of code to the User model...
37
+ ```ruby
38
+ gem 'prim'
39
+ ```
40
+
41
+ to your Gemfile. With __Prim__ we can just add a line of code to the User model...
38
42
 
39
43
  ```ruby
40
44
  class User < ActiveRecord::Base
data/lib/prim.rb CHANGED
@@ -27,11 +27,11 @@ module Prim
27
27
  Prim.configured_primaries << self.prim_relationships[ singular_name ]
28
28
 
29
29
  define_method "primary_#{ singular_name }" do
30
- get_primary(singular_name)
30
+ prim_collection_for(singular_name).primary
31
31
  end
32
32
 
33
- define_method "primary_#{ singular_name }=" do |record|
34
- assign_primary(singular_name, record)
33
+ define_method "primary_#{ singular_name }=" do |instance|
34
+ prim_collection_for(singular_name).primary = instance
35
35
  end
36
36
  end
37
37
  end
@@ -1,7 +1,7 @@
1
1
  module Prim
2
2
  # Collection largely wraps an association collection (like a Relation) but adds
3
3
  # the concept of a primary member. Collections can only exist in the context of
4
- # a Relationship (see Prim::Relationship for more info) and an `owner` instance,
4
+ # a Relationship (see Prim::Relationship for more info) and an "owning" `instance`,
5
5
  # and contain mapping records.
6
6
  class Collection
7
7
 
@@ -14,14 +14,20 @@ module Prim
14
14
  @instance = instance
15
15
  @relationship = relationship
16
16
 
17
- # Attach this collection to the mapping class so it has access to static methods.
18
- relationship.reflected_class.prim_collection = self
17
+ # Attach the relationship to the mapping class.
18
+ relationship.reflected_class.prim_relationship = relationship
19
19
  end
20
20
 
21
+ # Loads the primary member of this collection.
21
22
  def primary
22
- sources.where( relationship.through_reflection.name => { primary: true } ).first
23
+ sources.where( relationship.collection_label => { primary: true } ).first.try do |record|
24
+ record.primary = true
25
+ record
26
+ end
23
27
  end
24
28
 
29
+ # Sets the primary member of this collection. Requires a `source_record` to
30
+ # be passed (i.e. a Tag if Post `has_many :tags, through: :taggings`).
25
31
  def primary= source_record
26
32
  mapping = mapping_for(source_record)
27
33
 
@@ -40,18 +46,6 @@ module Prim
40
46
  true
41
47
  end
42
48
 
43
- def siblings_for mapping
44
- foreign_key = relationship.mapping_reflection.foreign_key
45
- mapping_type = relationship.mapping_reflection.type
46
- mapping_class = relationship.reflected_class
47
- primary_key = mapping_class.primary_key
48
-
49
- query = relationship.reflected_class.where( foreign_key => mapping[ foreign_key ] )
50
- query = query.where( mapping_type => mapping[ mapping_type ] ) unless mapping_type.nil?
51
-
52
- query.where( mapping_class.arel_table[ primary_key ].not_eq( mapping[ primary_key ] ) )
53
- end
54
-
55
49
  private
56
50
 
57
51
  # Creates a new source record and a mapping between it and the owner instance.
@@ -68,7 +62,7 @@ module Prim
68
62
  end
69
63
 
70
64
  def mappings force_reload = false
71
- instance.send( relationship.collection_method, force_reload )
65
+ instance.send( relationship.collection_label, force_reload )
72
66
  end
73
67
 
74
68
  def sources force_reload = false
@@ -5,15 +5,7 @@ module Prim
5
5
  module InstanceMethods
6
6
 
7
7
  module Owner
8
- def get_primary singular_name
9
- collection_for(singular_name).primary
10
- end
11
-
12
- def assign_primary singular_name, instance
13
- collection_for(singular_name).primary = instance
14
- end
15
-
16
- def collection_for singular_name
8
+ def prim_collection_for singular_name
17
9
  @_prim_collections ||= {}
18
10
  @_prim_collections[ singular_name ] ||= Prim::Collection.new(self.class.prim_relationships[ singular_name ], self)
19
11
  end
@@ -24,6 +16,10 @@ module Prim
24
16
 
25
17
  included do
26
18
  validate :only_one_primary
19
+
20
+ def self.primary
21
+ where( primary: true ).first
22
+ end
27
23
  end
28
24
 
29
25
  def only_one_primary
@@ -32,8 +28,42 @@ module Prim
32
28
  end
33
29
  end
34
30
 
31
+ # Builds a query selecting all siblings for a given mapping record. A record's
32
+ # siblings are any records in the table of the `reflected_class` that match
33
+ # the given record's foreign key and, if the association is polymorphic,
34
+ # its foreign type. The set of siblings *excludes* `self` (this record).
35
35
  def siblings
36
- prim_collection.siblings_for self
36
+ foreign_key = prim_relationship.mapping_reflection.foreign_key
37
+ mapping_type = prim_relationship.mapping_reflection.type
38
+ primary_key = prim_relationship.reflected_class.primary_key
39
+
40
+ # Select all by foreign key first, to handle all cases.
41
+ query = self.class.where( foreign_key => self[ foreign_key ] )
42
+
43
+ # Only select by a foreign "type" column if one is used on the `reflected_class`,
44
+ # making it a polymorphic association.
45
+ unless mapping_type.nil?
46
+ query = query.where( mapping_type => self[ mapping_type ] )
47
+ end
48
+
49
+ # Exclude this record from the query.
50
+ query.where( self.class.arel_table[ primary_key ].not_eq( self[ primary_key ] ) )
51
+ end
52
+ end
53
+
54
+ module Source
55
+ extend ActiveSupport::Concern
56
+
57
+ included do
58
+ attr_writer :primary
59
+
60
+ def primary
61
+ @primary || false
62
+ end
63
+
64
+ def primary?
65
+ primary
66
+ end
37
67
  end
38
68
  end
39
69
 
@@ -34,17 +34,19 @@ module Prim
34
34
  # TODO: ensure the association isn't nested?
35
35
 
36
36
  reflected_class.send :include, InstanceMethods::Reflected
37
- reflected_class.class_attribute :prim_collection
37
+ reflected_class.class_attribute :prim_relationship
38
+
39
+ source_class.send :include, InstanceMethods::Source if mapping_table?
38
40
  end
39
41
 
40
42
  # The association method to call on the owning class to retrieve a record's collection.
41
- def collection_method
43
+ def collection_label
42
44
  options[:through] || mapping_reflection.plural_name
43
45
  end
44
46
 
45
47
  # The class of the reflection source: i.e. Post if the owning class `has_many :posts`.
46
48
  def source_class
47
- source_reflection.klass
49
+ reflection.klass
48
50
  end
49
51
 
50
52
  # The class of the `mapping_reflection`.
@@ -55,7 +57,7 @@ module Prim
55
57
  # The association reflection representing the link between the owning class and the
56
58
  # mapping class, whether or not the mapping class represents a join-table.
57
59
  def mapping_reflection
58
- through_reflection || source_reflection
60
+ through_reflection || reflection
59
61
  end
60
62
 
61
63
  # True if this relationship relies on a mapping table for `primary` records.
data/prim.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "prim"
3
- s.version = "0.0.3"
4
- s.date = "2012-12-19"
3
+ s.version = "0.0.4"
4
+ s.date = "2013-01-02"
5
5
  s.summary = "Easily manage Rails associations that need a primary member."
6
6
  s.description = "With Prim it's easy to add a primary member to any one-to-many or many-to-many association. " +
7
7
  "Just add a short configuration to a model, generate and run a migration, and you're all set."
@@ -10,7 +10,8 @@ Gem::Specification.new do |s|
10
10
  s.files = `git ls-files`.split("\n")
11
11
  s.homepage = "https://github.com/orcahealth/prim"
12
12
 
13
- s.add_dependency "activerecord", "~> 3.2.0"
13
+ s.add_dependency "activerecord", "~> 3.2.0"
14
+ s.add_dependency "activesupport", "~> 3.2.0"
14
15
 
15
16
  s.require_paths = [ "lib" ]
16
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prim
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
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-12-19 00:00:00.000000000 Z
12
+ date: 2013-01-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -27,6 +27,22 @@ dependencies:
27
27
  - !ruby/object:Gem::Version
28
28
  version: 3.2.0
29
29
  none: false
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ prerelease: false
33
+ requirement: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 3.2.0
38
+ none: false
39
+ type: :runtime
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 3.2.0
45
+ none: false
30
46
  description: With Prim it's easy to add a primary member to any one-to-many or many-to-many
31
47
  association. Just add a short configuration to a model, generate and run a migration,
32
48
  and you're all set.
@@ -35,6 +51,7 @@ executables: []
35
51
  extensions: []
36
52
  extra_rdoc_files: []
37
53
  files:
54
+ - LICENSE
38
55
  - README.md
39
56
  - lib/prim.rb
40
57
  - lib/prim/collection.rb