meek 0.0.6

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: 2c750b14616a96016a9c9a1b3a657f8ef45187fa
4
+ data.tar.gz: df954f83e9a2da3fa618f16f8cc46e7e3a0a06d3
5
+ SHA512:
6
+ metadata.gz: 34365cb8d616720e157305f4661f44c62333c9b500512a2c3ca1f13c710e94a878c26505ce06cfaa8debc9815f677e3643415d732a5a5351fe6ed199e5eab342
7
+ data.tar.gz: 3d9f2b0b45325fb39b78b7a2510ccbdd7ea0c6f84aaa101f7cfb4e5ea72872fe51bee2a2228f5259a6d7bc1ac51ace6b40008518bb735e14e6952c14ae622934
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # SilverSpoon
2
+ In this world there are the has, and the has nots. ActiveRecord can `has_many` other ActiveRecords, but what about the rest of us? SilverSpoon lets ActiveRecord objects `has_many` Non-ActiveRecord objects, or for Non-ActiveRecord objects to `has_many` other Non-ActiveRecord objects.
3
+
4
+ For the people!
5
+
6
+ ## Suppose you have a plain old ActiveModel
7
+
8
+ class BankAccount
9
+ class << self
10
+ def find(args)
11
+ HTTP Request...
12
+ an arbitrary service...
13
+ or some awful local Modeling logic...
14
+ ...
15
+ end
16
+ end
17
+ end
18
+
19
+ ## And another Object that bares an association to it
20
+
21
+ class User < ActiveRecord::Base
22
+ extend SilverSpoon::ActiveConcern
23
+
24
+ has_many :bank_accounts
25
+ end
26
+
27
+ ## Now make calls a la ActiveRecord Association
28
+
29
+ user = User.new
30
+
31
+ user.bank_accounts
32
+
33
+ The referencing class does not have to be an ActiveRecord object. It simply needs to respond to a `find` method as you would expect. Having an `@id` or `to_params` would be useful as well in most cases. It would also be nice if there was a `save` method, if you're going to be doing something like that.
34
+
35
+ The `find` method may receive the id from the referring object to associate the two.
36
+
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ lib_path = File.expand_path('../../lib', __FILE__)
2
+ #ENV['RACK_ENV'] = ENV['RAILS_ENV'] = ENV['ODDZ_ENV'] ||= "development"
3
+ #require 'config/boot'
4
+ #Bundler::GemHelper.install_tasks if defined?(Bundler)
5
+ #require 'active_record'
6
+ #
7
+ require 'rspec/core'
8
+ require 'rspec/core/rake_task'
9
+ #require 'rspec/core/rake_task'
10
+ require 'active_record'
11
+ #
12
+ #Dir[File.join(File.dirname(__FILE__), 'lib/tasks/*.rake')].each {|f| load f }
13
+ #Dir[File.join(File.dirname(__FILE__), 'lib/tasks/**/*.rake')].each {|f| load f }
14
+ #include ActiveRecord::Tasks
15
+ #
16
+ ##Database
17
+ #dbconfig ||= YAML::load(ERB.new(File.read('config/database.yml')).result)
18
+ #dbenv = dbconfig[ENV["ODDZ_ENV"]]
19
+ #ENV["DATABASE_URL"] ||= "postgres://#{dbenv["username"]}:#{dbenv["password"]}@#{dbenv["host"]}:#{dbenv["port"]}/#{dbenv["database"]}"
20
+ #
21
+ #DatabaseTasks.env = ENV["ODDZ_ENV"]
22
+ #DatabaseTasks.seed_loader = SeedLoader.new
23
+ #DatabaseTasks.database_configuration = dbconfig
24
+ #DatabaseTasks.db_dir = 'db'
25
+ #DatabaseTasks.migrations_paths = 'db/migrate'
26
+ #DatabaseTasks.root = File.dirname(__FILE__)
27
+ #load 'active_record/railties/databases.rake'
28
+ #
29
+ desc "create database"
30
+ task :create_db do
31
+
32
+
33
+
34
+ #intentionally nothing
35
+ end
36
+ desc "Run all specs in spec directory (excluding plugin specs)"
37
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
38
+ task :default => :spec
39
+
40
+ #ActiveRecord::Base.configurations = dbconfig
41
+ #ActiveRecord::Base.establish_connection(
42
+ # :adapter => "sqlite3",
43
+ # :database => "activeworkaround.db"
44
+ #)
data/lib/meek.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'active_support'
2
+
3
+ require 'meek/errors'
4
+ require 'meek/concern'
5
+ require 'meek/active_concern'
6
+ require 'meek/proxy_association'
7
+ require 'meek/collection_proxy'
@@ -0,0 +1,13 @@
1
+ #presume it's an active record compliant object,
2
+ # abstract
3
+ module Meek
4
+ module ActiveConcern
5
+
6
+ class << self
7
+ def self.relation_delegate_class(_args)
8
+ Meek::CollectionProxy
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,58 @@
1
+ module Meek
2
+
3
+ class CollectionProxy
4
+ attr_accessor :owner, :model, :proxy_association
5
+
6
+ def initialize model, association
7
+ @proxy_association = Meek::ProxyAssociation.new(model, association)
8
+ end
9
+
10
+ delegate :[], :first, :second, :third, :fourth, :fifth, :forty_two,
11
+ :find, :select,
12
+ :last, :take, :count, :size, :length, :empty?, :any?, :many?, :include?,
13
+ :create, :create!, :build, :new,
14
+ to: :proxy_association
15
+
16
+ #replace, delete_all, destroy_all, delete, destroy, distinct, uniq,
17
+
18
+ def concat new
19
+ proxy_association.concat(new)
20
+ end
21
+
22
+ def <<(*records)
23
+ records.map {|record| record.save }
24
+ proxy_association.concat(records) && self
25
+ end
26
+ alias_method :push, :<<
27
+ alias_method :append, :<<
28
+
29
+ def prepend(*args)
30
+ raise NoMethodError, "prepend on association is not defined. Please use << or append"
31
+ end
32
+
33
+ # Equivalent to +delete_all+. The difference is that returns +self+, instead
34
+ # of an array with the deleted objects, so methods can be chained. See
35
+ # +delete_all+ for more information.
36
+ # Note that because +delete_all+ removes records by directly
37
+ # running an SQL query into the database, the +updated_at+ column of
38
+ # the object is not changed.
39
+ def clear
40
+ delete_all
41
+ self
42
+ end
43
+
44
+ # Reloads the collection from the database. Returns +self+.
45
+ def reload
46
+ proxy_association.reload
47
+ self
48
+ end
49
+
50
+ # Unloads the association. Returns +self+.
51
+ def reset
52
+ proxy_association.reset
53
+ proxy_association.reset_scope
54
+ self
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,52 @@
1
+ # presume it's an active record compliant object,
2
+ # abstract
3
+ module Meek
4
+ module Concern
5
+
6
+ def has_many(name, args={})
7
+ @@active_workaround_args ||= {}
8
+ @@active_workaround_args[:has_many] ||= {}
9
+ @@active_workaround_args[:has_many][name] = args
10
+ @@active_workaround_args[:has_many][name][:_attribute_name] = name
11
+
12
+ define_method(name) do
13
+ #return instance_variable_get(name) if does_cache && !instance_variable_get(name).nil?
14
+
15
+ args= @@active_workaround_args[:has_many][name]
16
+ msg = {}
17
+
18
+ foreign_key = args[:foreign_key] || ActiveSupport::Inflector.foreign_key(self.class.name)
19
+ msg[foreign_key] = respond_to?(:to_param) ? to_param : @id
20
+
21
+ klass_title = ActiveSupport::Inflector.classify( msg[:class_name] || name )
22
+ klass = args[:class] || ActiveSupport::Inflector.constantize(klass_title)
23
+
24
+ response = klass.find(:all, msg)
25
+ #instance_variable_set(name, response) if does_cache
26
+ response
27
+ end
28
+ end
29
+
30
+ def belongs_to(name, args={})
31
+ @@active_workaround_args ||= {}
32
+ @@active_workaround_args[:belongs_to] ||= {}
33
+ @@active_workaround_args[:belongs_to][name] = args
34
+ @@active_workaround_args[:belongs_to][name][:_attribute_name] = name
35
+
36
+ define_method(name) do
37
+
38
+ args= @@active_workaround_args[:belongs_to][name]
39
+ msg = {}
40
+
41
+ foreign_key = args[:foreign_key] || :id
42
+ msg[foreign_key] = respond_to?(:to_param) ? to_param : @id
43
+
44
+ klass_title = ActiveSupport::Inflector.classify(name)
45
+ klass = args[:class] || ActiveSupport::Inflector.constantize(klass_title)
46
+
47
+ klass.find(msg)
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,3 @@
1
+ module Meek
2
+ class NoDomain < StandardError; end
3
+ end
@@ -0,0 +1,51 @@
1
+ module Meek
2
+
3
+ class ProxyAssociation
4
+
5
+ attr_accessor :items
6
+
7
+ delegate :[], :first, :second, :third, :fourth, :fifth, :forty_two,
8
+ :find, :select,
9
+ :last, :take, :count, :size, :length, :empty?, :any?, :many?, :include?,
10
+ to: :items
11
+
12
+ def initialize( model, association )
13
+ @owner = association.owner
14
+ @model = model
15
+ reload
16
+ end
17
+
18
+ def create(args)
19
+ args[foriegn_key(@owner)] = @owner.to_param
20
+ @model.create(args)
21
+ end
22
+
23
+ def create!(args)
24
+ args[foriegn_key(@owner)] = @owner.to_param
25
+ @model.create!(args)
26
+ end
27
+
28
+ def build(args)
29
+ args[foriegn_key(@owner)] = @owner.to_param
30
+ @model.build(args)
31
+ end
32
+ alias_method :new, :build
33
+
34
+ def concat(new)
35
+ @items.concat(new)
36
+ end
37
+
38
+ def reload
39
+ @items = @model.find(:all, foriegn_key(@owner) => @owner.to_param)
40
+ end
41
+
42
+ #def reset
43
+ #end
44
+
45
+ #def reset_scope
46
+ #end
47
+
48
+ def foriegn_key(klass); ActiveSupport::Inflector.foreign_key(klass.class.name); end
49
+
50
+ end
51
+ end
@@ -0,0 +1,3 @@
1
+ module Meek
2
+ VERSION="0.0.6"
3
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe(Meek::ActiveConcern) do
4
+
5
+ describe("has_many") do
6
+
7
+ it("creates an object that responds to association") {
8
+ dummy = User.create(name: "bob")
9
+ expect(FundingInstrument).to receive(:find).with(:all, "user_id"=>dummy.id.to_s)
10
+ dummy.funding_instruments
11
+ }
12
+
13
+ it("returns as expected") {
14
+ dummy = User.create(name: "bob")
15
+ expect(dummy.funding_instruments).to be_a(Meek::CollectionProxy)
16
+ expect(dummy.funding_instruments[0]).to be(:a)
17
+
18
+ expect(dummy.funding_instruments.first).to be(:a)
19
+
20
+ [:size, :length, :count].each do |method|
21
+ expect(dummy.funding_instruments.send(method)).to be(2)
22
+ end
23
+
24
+ }
25
+
26
+ describe("new") do
27
+
28
+ it("builds") {
29
+ args = {:a => :b}
30
+ dummy = User.create(name: "bob")
31
+ expect(FundingInstrument).to receive(:build).with(args)
32
+ dummy.funding_instruments.build(args)
33
+ }
34
+
35
+ it("creates") {
36
+ args = {:a => :b}
37
+ dummy = User.create(name: "bob")
38
+ expect(FundingInstrument).to receive(:create).with(args)
39
+ dummy.funding_instruments.create(args)
40
+ }
41
+
42
+ it("creates!") {
43
+ args = {:a => :b}
44
+ dummy = User.create(name: "bob")
45
+ expect(FundingInstrument).to receive(:create!).with(args)
46
+ dummy.funding_instruments.create!(args)
47
+ }
48
+
49
+ it("concats") {
50
+ dummy = User.create(name: "bob")
51
+
52
+ child = Array.wrap( FundingInstrument.new() )
53
+ expect(dummy.funding_instruments.size).to eq(2)
54
+ dummy.funding_instruments.concat( child )
55
+ expect(dummy.funding_instruments.size).to eq(3)
56
+ }
57
+
58
+ it("pushes") {
59
+ dummy = User.create(name: "bob")
60
+
61
+ child = FundingInstrument.new()
62
+ expect(dummy.funding_instruments.size).to eq(2)
63
+ dummy.funding_instruments << child
64
+ expect(dummy.funding_instruments.size).to eq(3)
65
+ dummy.funding_instruments.push child
66
+ expect(dummy.funding_instruments.size).to eq(4)
67
+ dummy.funding_instruments.append child
68
+ expect(dummy.funding_instruments.size).to eq(5)
69
+ }
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe(Meek::Concern) do
4
+
5
+ describe("has_many") do
6
+
7
+ describe("finds a foreign_id") do
8
+
9
+ #it("prefers to_param") {
10
+ # dummy = User.new
11
+ # expect(FundingInstrument).to receive(:find).with(:all, "dummy_id"=>1)
12
+ # dummy.funding_instruments
13
+ #}
14
+
15
+ #it("defaults to @id") {
16
+ # dummy = UserWithoutToParam.new
17
+
18
+ # #expect(FundingInstrument).to receive(:find).with(:all, "dummy_without_to_param_id"=>1)
19
+ # #dummy.funding_instruments
20
+ #}
21
+
22
+ it("doesn't croak on no id") { skip("I'm lazy, put an id on it")
23
+ dummy = HorribleObject.new
24
+ #expect(FundingInstrument).to receive(:find).with(:all, {})
25
+ #dummy.funding_instruments
26
+ }
27
+
28
+ end
29
+
30
+ end
31
+
32
+ describe("belongs_to") do
33
+
34
+ it("creates an object that responds to association") {
35
+ dummy = SubservientDummy.new
36
+ #expect(ParentObject).to receive(:find).with(id:1)
37
+ dummy.parent_object
38
+ }
39
+
40
+ it("returns as expected") {
41
+ dummy = SubservientDummy.new
42
+ #expect(dummy.parent_object).to eq([:a, :b, :c])
43
+ }
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,49 @@
1
+ class FundingInstrument
2
+ # I'm a fake ActiveModel class!
3
+ def save
4
+ @persisted = true
5
+ end
6
+
7
+ # I should minimally respond to the #find method
8
+ class << self
9
+ def find(*args)
10
+ [:a, :b]
11
+ end
12
+
13
+ def relation_delegate_class(_args)
14
+ Meek::CollectionProxy
15
+ end
16
+ end
17
+ end
18
+
19
+ class ParentObject
20
+ extend Meek::ActiveConcern
21
+ def self.find(args)
22
+ [:a, :b, :c]
23
+ end
24
+ end
25
+
26
+ class User < ActiveRecord::Base
27
+
28
+ has_many :funding_instruments
29
+
30
+ end
31
+
32
+ class UserWithoutToParam < User
33
+
34
+ end
35
+
36
+ class HorribleObject < User
37
+
38
+ end
39
+
40
+ class SubservientDummy
41
+ extend Meek::Concern
42
+
43
+ def initialize
44
+ @id = 1
45
+ end
46
+
47
+ belongs_to :parent_object
48
+
49
+ end
@@ -0,0 +1,14 @@
1
+ lib_path = File.expand_path('../../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
3
+
4
+ require 'active_record'
5
+ require 'meek'
6
+
7
+ ActiveRecord::Base.establish_connection(
8
+ :adapter => "sqlite3",
9
+ :database => "./db/test.sqlite3"
10
+ )
11
+
12
+ # in spec/support/ and its subdirectories.
13
+ Dir.glob(File.join(File.dirname(__FILE__), './models', '*.rb')).each { |f| require f}
14
+ Dir.glob(File.join(File.dirname(__FILE__), 'support', '*.rb')).each { |f| require f}
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: meek
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
+ platform: ruby
6
+ authors:
7
+ - Trevor Grayson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ requirement: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - '>='
23
+ - !ruby/object:Gem::Version
24
+ version: '0'
25
+ prerelease: false
26
+ type: :runtime
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.0
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>='
37
+ - !ruby/object:Gem::Version
38
+ version: 2.0.0
39
+ prerelease: false
40
+ type: :development
41
+ description: This may go from ActiveRecord to Object or Object to ActiveRecord
42
+ email:
43
+ - trevor@trevorgrayson.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - README.md
49
+ - Rakefile
50
+ - lib/meek.rb
51
+ - lib/meek/active_concern.rb
52
+ - lib/meek/collection_proxy.rb
53
+ - lib/meek/concern.rb
54
+ - lib/meek/errors.rb
55
+ - lib/meek/proxy_association.rb
56
+ - lib/meek/version.rb
57
+ - spec/meek/active_concern_spec.rb
58
+ - spec/meek/concern_spec.rb
59
+ - spec/models/dummy.rb
60
+ - spec/spec_helper.rb
61
+ homepage: ''
62
+ licenses: []
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.2.2
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: Add has_many methods for non ActiveRecord associations.
84
+ test_files: []
85
+ has_rdoc: