meek 0.0.6

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: 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: