active_poro 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: