active_poro 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b4e43ea9ea78bdde2baab6cdbcac5c6ed70552c3
4
+ data.tar.gz: 6bac908f0f51f75a7a013044009b1ba8d24d2924
5
+ SHA512:
6
+ metadata.gz: b4fbe7a1ad8365b16d04c38eeaa692154405d1ce04aab34693367a9967f4aef917f19a372e80c248bce764ad43af133419a347a1e1d4d213d79429582c63957f
7
+ data.tar.gz: dcac90e161b9c14aeac187afa3e6eec17869a97c00d3da39d2c92eee14cfe7b2981bf8a62e6923317de0428b3e5ff458f765243913b01d3a8cf185850b49fdd8
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+
16
+ .idea/
17
+
18
+ ## UNIX TEMP FILES
19
+ *~
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --tag focus
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0-p247
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in active_poro.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Miguel Diaz
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # active_poro
2
+ Makes possible the use of has_many, has_one, belongs_to relations in POROs as you would expect
3
+
4
+ Important!
5
+ ----------
6
+
7
+ This project is under active development
8
+
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'active_poro'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install active_poro
25
+
26
+ ## Usage
27
+
28
+ You may use ActivePoro::Model as a mixin to enable relations/associations to be built between POROs
29
+ Currently supported associations:
30
+
31
+ - has_many
32
+ - has_one
33
+ - belongs_to
34
+
35
+ Example:
36
+
37
+ ```ruby
38
+ require 'active_poro'
39
+
40
+ class Dog
41
+ include ActivePoro::Model
42
+ has_many :fleas
43
+ end
44
+
45
+ class Flea
46
+ include ActivePoro::Model
47
+ belongs_to :dog
48
+ end
49
+ ```
50
+
51
+ Now, with that in place you should be able to do
52
+
53
+ ```ruby
54
+ dog = Dog.new
55
+ flea_a = Flew.new
56
+ flea_b = Flew.new
57
+
58
+ # associate the fleas with the dog
59
+ dog.fleas = [flea_a, flea_b]
60
+
61
+ # now fleas have the dog associated back
62
+ flea_a.dog == dog
63
+ #=> true
64
+
65
+ # now fleas have the dog associated back
66
+ flea_b.dog == dog
67
+ #=> true
68
+
69
+ # if a new dog is created
70
+ another_dog = Dog.new
71
+
72
+ # and flea_b for example, jumps to it (i.e. is associated to this other dog)
73
+ flea_b.dog = another_dog
74
+
75
+ # then dog does not have flea_b now
76
+ dog.fleas
77
+ #=> [flea_a] # simplified output, not actual output on the console
78
+
79
+ # and another_dog gets flea_b
80
+ another_dog.fleas
81
+
82
+ #=> [flea_b] # simplified output, not actual output on the console
83
+ ```
84
+
85
+ ## Contributing
86
+
87
+ 1. Fork it ( https://github.com/codescrum/active_poro/fork )
88
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
89
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
90
+ 4. Push to the branch (`git push origin my-new-feature`)
91
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'active_poro/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "active_poro"
8
+ spec.version = ActivePoro::VERSION
9
+ spec.authors = ["Miguel Diaz"]
10
+ spec.email = ["miguel.diaz@codescrum.com"]
11
+ spec.summary = %q{Makes possible the use of has_many, has_one, belongs_to relations in POROs as you would expect.}
12
+ spec.description = %q{Ever wanted to have active-record like relations in your POROs?, here is a proposed solution.}
13
+ spec.homepage = "https://github.com/codescrum/active_poro"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency('rspec')
24
+ spec.add_development_dependency('jazz_hands')
25
+
26
+ spec.add_runtime_dependency('activesupport')
27
+ end
@@ -0,0 +1,6 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext/string'
3
+
4
+ require 'active_poro/relations'
5
+ require 'active_poro/model'
6
+ require 'active_poro/version'
@@ -0,0 +1,6 @@
1
+ module ActivePoro
2
+ module Model
3
+ extend ActiveSupport::Concern
4
+ include Relations
5
+ end
6
+ end
@@ -0,0 +1,102 @@
1
+ module ActivePoro
2
+ module Relations
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def has_many(target_name)
7
+ # define getter method
8
+ define_method target_name do
9
+ instance_variable_get("@#{target_name}") || []
10
+ end
11
+
12
+ # define setter method
13
+ define_method "#{target_name}=" do |members|
14
+ # set the instance variable only if I am now the rightful owner
15
+ instance_variable_set("@#{target_name}", members || [])
16
+ reflected_association_name = self.class.name.underscore
17
+ members.each do |member|
18
+
19
+ current_owner = member.send(reflected_association_name)
20
+ if current_owner.nil? # no current assignment
21
+ member.send "#{reflected_association_name}=", self
22
+ elsif current_owner != self # current assignment is not me
23
+ other_members = current_owner.send target_name
24
+ if other_members.include?(member)
25
+ # take the element from the other member
26
+ new_members = other_members - [member]
27
+ current_owner.send "#{target_name}=", new_members
28
+ else
29
+ raise "Unmatching association; Current owner (#{current_owner.class.name}) of #{member.class.name} does not have it as a member"
30
+ end
31
+ # add me as associated to the member I am also including
32
+ member.send "#{reflected_association_name}=", self
33
+ else
34
+ # its already me, do not do anything
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+
41
+ def has_one(target_name)
42
+ # define getter method
43
+ define_method target_name do
44
+ instance_variable_get("@#{target_name}") || []
45
+ end
46
+
47
+ # define setter method
48
+ define_method "#{target_name}=" do |member|
49
+ reflected_association_name = self.class.name.underscore
50
+ unless member.send(reflected_association_name) == self
51
+ member.send "#{reflected_association_name}=", self
52
+ end
53
+ instance_variable_set("@#{target_name}", member || [])
54
+ end
55
+ end
56
+
57
+ def belongs_to(target_name)
58
+ # define getter method
59
+ define_method target_name do
60
+ instance_variable_get("@#{target_name}")
61
+ end
62
+
63
+ # define setter method
64
+ define_method "#{target_name}=" do |member|
65
+ previous_member = instance_variable_get("@#{target_name}")
66
+ instance_variable_set("@#{target_name}", member)
67
+ reflected_association_name = self.class.name.underscore
68
+ # add myself to reflected association
69
+ if member.respond_to? reflected_association_name
70
+ unless member.send(reflected_association_name) == self
71
+ member.send("#{reflected_association_name}=", self)
72
+ end
73
+ elsif member.respond_to? reflected_association_name.pluralize
74
+ reflected_members = member.send(reflected_association_name.pluralize)
75
+ unless reflected_members.include? self
76
+ member.send("#{reflected_association_name.pluralize}=", reflected_members + [self])
77
+ end
78
+ else
79
+ raise "Association definition missing: no #{reflected_association_name} or #{reflected_association_name.pluralize} association defined in #{member.class}"
80
+ end
81
+
82
+ # remove myself from old reflected association
83
+ if previous_member.respond_to? reflected_association_name
84
+ if previous_member.send(reflected_association_name) == self
85
+ previous_member.send("#{reflected_association_name}=", nil)
86
+ end
87
+ elsif previous_member.respond_to? reflected_association_name.pluralize
88
+ previous_reflected_members = previous_member.send(reflected_association_name.pluralize)
89
+ if previous_reflected_members.include? self
90
+ previous_member.send("#{reflected_association_name.pluralize}=", previous_reflected_members - [self])
91
+ end
92
+ elsif previous_member.nil?
93
+ # there was not previous member
94
+ else # there was a previous member
95
+ raise "Ghost association definition: no #{reflected_association_name} or #{reflected_association_name.pluralize} association defined in #{member.class}, although it was there previously, dirty contamination"
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,3 @@
1
+ module ActivePoro
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'ActivePoro' do
4
+ context 'Model' do
5
+ context 'relations' do
6
+ before do
7
+ class Dog < BaseTestClass
8
+ include ActivePoro::Model
9
+ has_many :fleas
10
+ end
11
+
12
+ class Flea < BaseTestClass
13
+ include ActivePoro::Model
14
+ belongs_to :dog
15
+ end
16
+ end
17
+
18
+ let(:big_dog){ Dog.new('Big big_dog') }
19
+ let(:flea_a){ Flea.new('A') }
20
+ let(:flea_b){ Flea.new('B') }
21
+
22
+ context 'when dog gets fleas' do
23
+ let(:dog_with_fleas) do
24
+ big_dog.fleas = [flea_a, flea_b]
25
+ big_dog
26
+ end
27
+
28
+ it 'initializes with an empty array of fleas' do
29
+ expect(big_dog.fleas).to eq([])
30
+ end
31
+
32
+ it 'is directly associated with pre-existant fleas' do
33
+ expect(dog_with_fleas.fleas).to eq([flea_a, flea_b])
34
+ end
35
+
36
+ it 'correctly sets the right big_dog to each flea' do
37
+ dog_with_fleas.fleas.each do |flea|
38
+ expect(flea.dog).to eq(big_dog)
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'when fleas jump onto big_dog' do
44
+ it 'fleas have no dog to begin with' do
45
+ expect(flea_a.dog).to be_nil
46
+ end
47
+
48
+ it 'fleas may have the big_dog associated to them and viceversa' do
49
+ flea_a.dog = big_dog
50
+ expect(flea_a.dog).to eq(big_dog)
51
+ expect(big_dog.fleas).to eq([flea_a])
52
+
53
+ flea_b.dog = big_dog
54
+ expect(flea_b.dog).to eq(big_dog)
55
+ expect(big_dog.fleas).to eq([flea_a, flea_b])
56
+ end
57
+
58
+ end
59
+
60
+ context 'when a flea jumps between dogs' do
61
+
62
+ let(:small_dog){ Dog.new('Small dog') }
63
+
64
+ it 'cannot be in two dogs at the same time' do
65
+ flea_a.dog = big_dog
66
+ expect(flea_a.dog).to eq(big_dog)
67
+ expect(big_dog.fleas).to eq([flea_a])
68
+
69
+ # flea jumps from big dog to small dog
70
+ flea_a.dog = small_dog
71
+ expect(flea_a.dog).to eq(small_dog)
72
+ expect(small_dog.fleas).to eq([flea_a])
73
+
74
+ # flea A no longer in big dog
75
+ expect(big_dog.fleas).to_not include(flea_a)
76
+ expect(big_dog.fleas).to be_empty # sanity check
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+
3
+ ######################
4
+ require 'active_poro'#
5
+ ######################
6
+
7
+ # require everything in spec/support
8
+ Dir[File.expand_path('spec/support/**/*.rb')].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+ config.filter_run :focus => true
12
+ config.run_all_when_everything_filtered = true
13
+ end
@@ -0,0 +1,17 @@
1
+ # this is just a class that includes convenience methods for testing
2
+ # such as a giving it a name so that is easy to inspect
3
+ class BaseTestClass
4
+ attr_accessor :name
5
+
6
+ def initialize(name)
7
+ self.name = name
8
+ end
9
+
10
+ def to_s
11
+ name
12
+ end
13
+
14
+ def inspect
15
+ "\"#{to_s}\""
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_poro
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Miguel Diaz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: jazz_hands
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Ever wanted to have active-record like relations in your POROs?, here
84
+ is a proposed solution.
85
+ email:
86
+ - miguel.diaz@codescrum.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - .rspec
93
+ - .ruby-version
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - active_poro.gemspec
99
+ - lib/active_poro.rb
100
+ - lib/active_poro/model.rb
101
+ - lib/active_poro/relations.rb
102
+ - lib/active_poro/version.rb
103
+ - spec/active_poro_spec.rb
104
+ - spec/spec_helper.rb
105
+ - spec/support/base_test_class.rb
106
+ homepage: https://github.com/codescrum/active_poro
107
+ licenses:
108
+ - MIT
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.0.3
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Makes possible the use of has_many, has_one, belongs_to relations in POROs
130
+ as you would expect.
131
+ test_files:
132
+ - spec/active_poro_spec.rb
133
+ - spec/spec_helper.rb
134
+ - spec/support/base_test_class.rb
135
+ has_rdoc: