reactive-record 0.7.0

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: c14856b73501aab70804ad8351301b87b948fd75
4
+ data.tar.gz: b0aef64c154ca72e6af956a1966e0e77235bafec
5
+ SHA512:
6
+ metadata.gz: bcc0cdea12ce7c93e27b6179ed6c2842207cf7e046bef8da8eb46643a2adf6964fad1e6d4d0f3c75853bf661de19142f28c987352b4f16abe03fbacdab8464a2
7
+ data.tar.gz: f861152c0a4ca7fda801ccf5ee5b8603a7c50a40c8d19506d9c90c71d68c732b99e092da468aa951577341b9f2056c0a89c85d102fdfd192824b814ec92fc6ad
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = ReactiveRecord
2
+
3
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
8
+ load 'rails/tasks/engine.rake'
9
+ Bundler::GemHelper.install_tasks
10
+ Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
11
+ require 'rspec/core'
12
+ require 'rspec/core/rake_task'
13
+ desc "Run all specs in spec directory (excluding plugin specs)"
14
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
15
+
16
+ require 'opal/rspec/rake_task'
17
+ require 'bundler'
18
+ Bundler.require
19
+
20
+ # Add our opal/ directory to the load path
21
+ #Opal.append_path File.expand_path('../lib', __FILE__)
22
+
23
+ Opal::RSpec::RakeTask.new(:spec_opal) do |s|
24
+ s.sprockets.paths.tap { s.sprockets.clear_paths }[0..-2].each { |path| s.sprockets.append_path path}
25
+ s.main = 'sprockets_runner'
26
+ s.append_path 'spec-opal'
27
+ end
28
+
29
+ task :default => [:spec, :spec_opal]
@@ -0,0 +1,4 @@
1
+ module ReactiveRecord
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,22 @@
1
+ require 'reactive_record/server_data_cache'
2
+
3
+ module ReactiveRecord
4
+
5
+ class ReactiveRecordController < ApplicationController
6
+
7
+ def fetch
8
+ render :json => ReactiveRecord::ServerDataCache[params[:pending_fetches]]
9
+ end
10
+
11
+
12
+ def save
13
+ render :json => ReactiveRecord::Base.save_records(params[:models], params[:associations])
14
+ end
15
+
16
+ def destroy
17
+ render :json => ReactiveRecord::Base.destroy_record(params[:model], params[:id], params[:vector])
18
+ end
19
+
20
+ end
21
+
22
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ ReactiveRecord::Engine.routes.draw do
2
+ root :to => "reactive_record#fetch", via: :post
3
+ match 'save', to: 'reactive_record#save', via: :post
4
+ match 'destroy', to: 'reactive_record#destroy', via: :post
5
+ end
data/lib/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Declare your gem's dependencies in reactive_record.gemspec.
4
+ # Bundler will treat runtime dependencies like base dependencies, and
5
+ # development dependencies will be added by default to the :development group.
6
+ gemspec
7
+
8
+ # jquery-rails is used by the dummy application
9
+ gem "jquery-rails"
10
+
11
+ # Declare any dependencies that are still in development here instead of in
12
+ # your gemspec. These might include edge Rails or gems from your path or
13
+ # Git. Remember to move these dependencies to your gemspec before releasing
14
+ # your gem to rubygems.org.
15
+
16
+ # To use debugger
17
+ # gem 'debugger'
@@ -0,0 +1,28 @@
1
+ if RUBY_ENGINE == 'opal'
2
+
3
+ require "opal-react"
4
+ require "reactive_record/server_data_cache"
5
+ require "reactive_record/active_record/reactive_record/while_loading"
6
+ require "reactive_record/active_record/reactive_record/isomorphic_base"
7
+ require "reactive_record/active_record/aggregations"
8
+ require "reactive_record/active_record/associations"
9
+ require "reactive_record/active_record/reactive_record/base"
10
+ require "reactive_record/active_record/reactive_record/collection"
11
+ require "reactive_record/active_record/class_methods"
12
+ require "reactive_record/active_record/instance_methods"
13
+ require "reactive_record/active_record/base"
14
+ require "reactive_record/interval"
15
+
16
+ else
17
+
18
+ require "opal"
19
+ require "reactive_record/version"
20
+ require "reactive_record/engine"
21
+ require "reactive_record/server_data_cache"
22
+ require "reactive_record/active_record/reactive_record/isomorphic_base"
23
+ require "reactive_record/serializers"
24
+
25
+ Opal.append_path File.expand_path('../', __FILE__).untaint
26
+ Opal.append_path File.expand_path('../../vendor', __FILE__).untaint
27
+
28
+ end
@@ -0,0 +1,38 @@
1
+ module ActiveRecord
2
+
3
+ class Base
4
+
5
+ def self.reflect_on_all_aggregations
6
+ base_class.instance_eval { @aggregations ||= [] }
7
+ end
8
+
9
+ def self.reflect_on_aggregation(attribute)
10
+ reflect_on_all_aggregations.detect { |aggregation| aggregation.attribute == attribute }
11
+ end
12
+
13
+ end
14
+
15
+ module Aggregations
16
+
17
+ class AggregationReflection
18
+
19
+ attr_reader :klass_name
20
+ attr_reader :attribute
21
+
22
+ def initialize(owner_class, macro, name, options = {})
23
+ owner_class.reflect_on_all_aggregations << self
24
+ @owner_class = owner_class
25
+ @klass_name = options[:class_name] || name.camelize
26
+ @attribute = name
27
+ end
28
+
29
+ def klass
30
+ @klass ||= Object.const_get(@klass_name)
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+
38
+ end
@@ -0,0 +1,54 @@
1
+ module ActiveRecord
2
+
3
+ class Base
4
+
5
+ def self.reflect_on_all_associations
6
+ base_class.instance_eval { @associations ||= superclass.instance_eval { (@associations && @associations.dup) || [] } }
7
+ end
8
+
9
+ def self.reflect_on_association(attribute)
10
+ reflect_on_all_associations.detect { |association| association.attribute == attribute }
11
+ end
12
+
13
+ end
14
+
15
+ module Associations
16
+
17
+ class AssociationReflection
18
+
19
+ attr_reader :association_foreign_key
20
+ attr_reader :attribute
21
+ attr_reader :macro
22
+
23
+ def initialize(owner_class, macro, name, options = {})
24
+ owner_class.reflect_on_all_associations << self
25
+ @owner_class = owner_class
26
+ @macro = macro
27
+ @klass_name = options[:class_name] || (collection? && name.camelize.gsub(/s$/,"")) || name.camelize
28
+ @association_foreign_key = options[:foreign_key] || (macro == :belongs_to && "#{name}_id") || "#{@owner_class.name.underscore}_id"
29
+ @attribute = name
30
+ end
31
+
32
+ def inverse_of
33
+ unless @inverse_of
34
+ inverse_association = klass.reflect_on_all_associations.detect { | association | association.association_foreign_key == @association_foreign_key }
35
+ raise "Association #{@owner_class}.#{attribute} (foreign_key: #{@association_foreign_key}) has no inverse in #{@klass_name}" unless inverse_association
36
+ @inverse_of = inverse_association.attribute
37
+ end
38
+ @inverse_of
39
+ end
40
+
41
+ def klass
42
+ @klass ||= Object.const_get(@klass_name)
43
+ end
44
+
45
+ def collection?
46
+ [:has_many].include? @macro
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+
54
+ end
@@ -0,0 +1,9 @@
1
+ module ActiveRecord
2
+ class Base
3
+
4
+ extend ClassMethods
5
+
6
+ include InstanceMethods
7
+
8
+ end
9
+ end
@@ -0,0 +1,113 @@
1
+ module ActiveRecord
2
+
3
+ module ClassMethods
4
+
5
+ def base_class
6
+
7
+ unless self < Base
8
+ raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
9
+ end
10
+
11
+ if superclass == Base || superclass.abstract_class?
12
+ self
13
+ else
14
+ superclass.base_class
15
+ end
16
+
17
+ end
18
+
19
+ def abstract_class?
20
+ defined?(@abstract_class) && @abstract_class == true
21
+ end
22
+
23
+ def primary_key
24
+ base_class.instance_eval { @primary_key_value || :id }
25
+ end
26
+
27
+ def primary_key=(val)
28
+ base_class.instance_eval { @primary_key_value = val }
29
+ end
30
+
31
+ def inheritance_column
32
+ base_class.instance_eval {@inheritance_column_value || "type"}
33
+ end
34
+
35
+ def inheritance_column=(name)
36
+ base_class.instance_eval {@inheritance_column_value = name}
37
+ end
38
+
39
+ def model_name
40
+ # in reality should return ActiveModel::Name object, blah blah
41
+ name
42
+ end
43
+
44
+ def find(id)
45
+ base_class.instance_eval {ReactiveRecord::Base.find(self, primary_key, id)}
46
+ end
47
+
48
+ def find_by(opts = {})
49
+ base_class.instance_eval {ReactiveRecord::Base.find(self, opts.first.first, opts.first.last)}
50
+ end
51
+
52
+ def method_missing(name, *args, &block)
53
+ if args.count == 1 && name =~ /^find_by_/ && !block
54
+ find_by(name.gsub(/^find_by_/, "") => args[0])
55
+ else
56
+ raise "#{self.name}.#{name}(#{args}) (called class method missing)"
57
+ end
58
+ end
59
+
60
+ def abstract_class=(val)
61
+ @abstract_class = val
62
+ end
63
+
64
+ def scope(name, body)
65
+ singleton_class.send(:define_method, name) { ReactiveRecord::Collection.new(self, nil, nil, self, name) }
66
+ end
67
+
68
+ def all
69
+ ReactiveRecord::Collection.new(self)
70
+ end
71
+
72
+ [:belongs_to, :has_many, :has_one].each do |macro|
73
+ define_method(macro) do |name, opts = {}|
74
+ Associations::AssociationReflection.new(base_class, macro, name, opts)
75
+ end
76
+ end
77
+
78
+ def composed_of(name, opts = {})
79
+ Aggregations::AggregationReflection.new(base_class, :composed_of, name, opts)
80
+ end
81
+
82
+ [
83
+ "table_name=", "before_validation", "with_options", "validates_presence_of", "validates_format_of",
84
+ "accepts_nested_attributes_for", "after_create", "before_save", "before_destroy", "where", "validate",
85
+ "attr_protected", "validates_numericality_of", "default_scope", "has_attached_file", "attr_accessible",
86
+ "serialize"
87
+ ].each do |method|
88
+ define_method(method.to_s) { |*args, &block| }
89
+ end
90
+
91
+ def _react_param_conversion(param, opt = nil)
92
+ # defines how react will convert incoming json to this ActiveRecord model
93
+ param_is_native = !param.respond_to?(:is_a?) rescue true
94
+ param = JSON.from_object param if param_is_native
95
+ if param.is_a? self
96
+ param
97
+ elsif param.is_a? Hash
98
+ if opt == :validate_only
99
+ ReactiveRecord::Base.infer_type_from_hash(self, param) == self
100
+ else
101
+ target = find(param[primary_key])
102
+ param.each { |key, value| param[key] = [value] }
103
+ ReactiveRecord::Base.load_from_json(param, target)
104
+ target
105
+ end
106
+ else
107
+ nil
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ end
@@ -0,0 +1,76 @@
1
+ module ActiveRecord
2
+
3
+ module InstanceMethods
4
+
5
+ def attributes
6
+ @backing_record.attributes
7
+ end
8
+
9
+ def initialize(hash = {})
10
+ if hash.is_a? ReactiveRecord::Base
11
+ @backing_record = hash
12
+ else
13
+ # standard active_record new -> creates a new instance, primary key is ignored if present
14
+ hash[primary_key] = nil
15
+ @backing_record = ReactiveRecord::Base.new(self.class, hash, self)
16
+ end
17
+ end
18
+
19
+ def primary_key
20
+ self.class.primary_key
21
+ end
22
+
23
+ def id
24
+ @backing_record.reactive_get!(primary_key)
25
+ end
26
+
27
+ def id=(value)
28
+ @backing_record.id = value
29
+ end
30
+
31
+ def model_name
32
+ # in reality should return ActiveModel::Name object, blah blah
33
+ self.class.model_name
34
+ end
35
+
36
+ def revert
37
+ @backing_record.revert
38
+ end
39
+
40
+ def changed?
41
+ @backing_record.changed?
42
+ end
43
+
44
+ def ==(ar_instance)
45
+ @backing_record == ar_instance.instance_eval { @backing_record }
46
+ end
47
+
48
+ def method_missing(name, *args, &block)
49
+ if name =~ /_changed\?$/
50
+ @backing_record.changed?(name.gsub(/_changed\?$/,""))
51
+ elsif args.count == 1 && name =~ /=$/ && !block
52
+ attribute_name = name.gsub(/=$/,"")
53
+ @backing_record.reactive_set!(attribute_name, args[0])
54
+ elsif args.count == 0 && !block
55
+ @backing_record.reactive_get!(name)
56
+ else
57
+ super
58
+ end
59
+ end
60
+
61
+ def save(&block)
62
+ @backing_record.save &block
63
+ end
64
+
65
+ def saving?
66
+ @backing_record.saving?
67
+ end
68
+
69
+ def destroy(&block)
70
+ @backing_record.destroy &block
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+