nube 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,42 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /doc/
6
+ /spec/reports/
7
+
8
+ *.rbc
9
+ capybara-*.html
10
+ .rspec
11
+ /log
12
+ /tmp
13
+ /db/*.sqlite3
14
+ /db/*.sqlite3-journal
15
+ /public/system
16
+ /coverage/
17
+ /spec/tmp
18
+ **.orig
19
+ rerun.txt
20
+ pickle-email-*.html
21
+
22
+ # TODO Comment out these rules if you are OK with secrets being uploaded to the repo
23
+ config/initializers/secret_token.rb
24
+ config/secrets.yml
25
+
26
+ ## Environment normalization:
27
+ /.bundle
28
+ /vendor/bundle
29
+
30
+ # these should all be checked in to normalize the environment:
31
+ # Gemfile.lock, .ruby-version, .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
35
+
36
+ # if using bower-rails ignore default bower_components path bower.json files
37
+ /vendor/assets/bower_components
38
+ *.bowerrc
39
+ bower.json
40
+
41
+ # Ignore pow environment settings
42
+ .powenv
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.4
4
+ before_install: gem install bundler -v 1.11.2
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at gab.edera@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nube.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Ga6ix
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 g.edera
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # Nube
2
+ Working with remote objects as activerecord
3
+
4
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/nube`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+
6
+ TODO: Delete this and the text above, and describe your gem
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'nube'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install nube
23
+
24
+ ## Usage
25
+
26
+ TODO: Write usage instructions here
27
+
28
+ ## Development
29
+
30
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
31
+
32
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
33
+
34
+ ## Contributing
35
+
36
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/nube. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
37
+
38
+
39
+ ## License
40
+
41
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "nube"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/nube/base.rb ADDED
@@ -0,0 +1,134 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ # require 'active_support'
4
+ require 'active_support/core_ext/string'
5
+ # require 'active_model'
6
+
7
+ module Nube
8
+ class Base
9
+ attr_reader :new_record
10
+ attr_accessor :attributes, :attrs_changed, :errors
11
+
12
+ alias_method :new_record?, :new_record
13
+
14
+ def self.inherited(subclass)
15
+ subclass.include(Site)
16
+ subclass.include(RemoteScope)
17
+ subclass.include(RemoteAssociation)
18
+ end
19
+
20
+ def initialize attrs={}, new_record=true
21
+ @new_record = new_record
22
+ @attrs_changed = {}
23
+ @errors = {}
24
+ @attributes = (attrs.empty? ? self.class.empty_attributes : attrs).stringify_keys
25
+ end
26
+
27
+ def save(params={})
28
+ if new_record?
29
+ remote_obj = self.class.post(self.class.site({ controller: self.class.name.pluralize.underscore }, params.merge(identity)), { attributes: @attributes } ).first
30
+ @attributes = remote_obj["object"]
31
+ @errors = remote_obj["errors"]
32
+ @new_record = false if @errors.empty?
33
+ else
34
+ @errors = self.class.put(self.class.site({ controller: self.class.name.pluralize.underscore, id: id }, params.merge(identity)), { attributes: @attrs_changed } ).first
35
+ end
36
+ @errors.empty?
37
+ end
38
+
39
+ def update_attributes(attrs={})
40
+ @attrs_changed.merge!(attrs)
41
+ save
42
+ end
43
+
44
+ def update_attribute(attr, value)
45
+ update_attributes(attr => value)
46
+ end
47
+
48
+ def destroy
49
+ self.class.destroy_all(id: id).first unless id.nil?
50
+ end
51
+
52
+ ["get","post","put","delete"].each do |method|
53
+ define_singleton_method method do |site, params={}|
54
+ do_request(method, site, params)
55
+ end
56
+ end
57
+
58
+ def identity
59
+ _identity = nil
60
+ _identity = if defined?(IDENTITY_ATTR)
61
+ send(IDENTITY_ATTR)
62
+ elsif defined?(IDENTITY_SITE)
63
+ IDENTITY_SITE
64
+ end
65
+ _identity.nil? ? {} : { identity: _identity }
66
+ end
67
+
68
+ def inspect
69
+ "#<#{self.class.name} " + attributes.keys.map{|attr| "#{attr}: #{attributes[attr].inspect}" }.join(', ') + '>'
70
+ end
71
+
72
+ # def model_name
73
+ # ActiveModel::Name.new self.class
74
+ # end
75
+
76
+ # def to_key
77
+ # [id] if id
78
+ # end
79
+
80
+ # def to_model
81
+ # self
82
+ # end
83
+
84
+ # def self.column_names
85
+ # new.attributes.keys
86
+ # end
87
+
88
+ # alias_method :persisted?, :new_record?
89
+
90
+ def self.enum(options)
91
+ options.each do |attr, values|
92
+ values.each do |value|
93
+ define_method "#{value}?" do
94
+ self.send(attr) == value.to_s
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ def self.do_request(method, site, params={})
101
+ url = URI.parse(site)
102
+ req = "Net::HTTP::#{method.to_s.camelize}".constantize.new(url.to_s)
103
+ req.body = params.to_param
104
+ res = Net::HTTP.start(url.host, url.port) {|http| http.request(req) }
105
+ if (res.code == "200")
106
+ [JSON.parse(res.body, quirks_mode: true)].flatten.compact
107
+ else
108
+ raise res.msg + res.code
109
+ end
110
+ end
111
+
112
+ def method_missing(name, *args, &block)
113
+ name = name.to_s
114
+ setter = name.end_with?('=')
115
+ name = name[0..-2] if setter
116
+ if @attributes.has_key?(name)
117
+ if setter
118
+ @attributes[name] = args[0]
119
+ @attrs_changed[name] = args[0]
120
+ else
121
+ @attributes[name]
122
+ end
123
+ else
124
+ super
125
+ end
126
+ end
127
+
128
+ def self.method_missing(name, *args, &block)
129
+ super(name, *args) unless ("#{self.name}Relation".constantize.instance_methods - self.instance_methods).include?(name)
130
+ args.empty? ? self.node.send(name) : self.node.send(name, args.first)
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,92 @@
1
+ module NubeController
2
+ extend ActiveSupport::Concern
3
+
4
+ def resource
5
+ defined?(self.class::RESOURCE) ? self.class::RESOURCE : controller_name.singularize.camelize.constantize
6
+ end
7
+
8
+ def index
9
+ render json: apply_scopes
10
+ end
11
+
12
+ def count; render json: apply_scopes.count; end
13
+
14
+ def create
15
+ obj = resource.create(attributes)
16
+ render json: { object: obj.attributes, errors: obj.errors.messages }
17
+ end
18
+
19
+ def update
20
+ obj = resource.find(params[:id])
21
+ obj.update_attributes(attributes)
22
+ render json: obj.errors.messages
23
+ end
24
+
25
+ def update_all; render json: apply_scopes.update_all(params[:changes]); end
26
+
27
+ def destroy_all; render json: apply_scopes.destroy_all; end
28
+
29
+ def massive_sum; resource.massive_sum(transaction); end
30
+
31
+ def massive_update; resource.massive_update(transaction); end
32
+
33
+ def massive_creation; resource.massive_creation(transaction); end
34
+
35
+ def empty_attributes; render json: resource.new ; end
36
+
37
+ private
38
+
39
+ def self.resource(xmodel); @@resource = xmodel; end
40
+
41
+ def apply_relations; @resource = @resource.where(relations).where(params[:server_id]); end
42
+
43
+ def parse_request; @json = JSON.parse(request.body.read); end
44
+
45
+ def apply_joins; @resource = @resource.joins(joins); end
46
+
47
+ def apply_scope; scopes.each { |key, value| @resource = value.is_a?(Hash) ? @resource.send(key, *value.values) : @resource.send(key) }; end
48
+
49
+ def apply_limit; @resource = @resource.limit(limit); end
50
+
51
+ def apply_offset; @resource = @resource.offset(offset); end
52
+
53
+ def apply_where; where.each { |condition| @resource = @resource.where(condition) }; end
54
+
55
+ def apply_order; order.each { |condition| @resource = @resource.order(condition) }; end
56
+
57
+ def apply_search; @resource = @resource.search(search).result; end
58
+
59
+ def transaction; params.has_key?(:transaction) ? (params.require(:transaction).is_a?(Hash) ? params.require(:transaction).permit! : params[:transaction]) : {}; end
60
+
61
+ def attributes; params.has_key?(:attributes) ? params.require(:attributes).permit!: {}; end
62
+
63
+ def relations; params.has_key?(:relations) ? params.require(:relations).permit! : {}; end
64
+
65
+ def scopes; params.has_key?(:scopes) ? params.require(:scopes).permit! : {}; end
66
+
67
+ def joins; params.has_key?(:joins) ? params.require(:joins).map(&:to_sym): []; end
68
+
69
+ def where; params.has_key?(:where) ? params.require(:where).map{|con| con.is_a?(Hash) ? con.permit! : con } : []; end
70
+
71
+ def order; params.has_key?(:order) ? params.require(:order).map{|con| con.is_a?(Hash) ? con.permit! : con } : []; end
72
+
73
+ def limit; params.has_key?(:limit) ? params[:limit].to_i : nil; end
74
+
75
+ def offset; params.has_key?(:offset) ? params[:offset].to_i : nil; end
76
+
77
+ def search; params.has_key?(:search) ? params.require(:search).permit! : {}; end
78
+
79
+ def apply_scopes
80
+ @resource = resource
81
+ apply_search
82
+ apply_relations
83
+ apply_joins
84
+ apply_scope
85
+ apply_where
86
+ apply_order
87
+ apply_limit
88
+ apply_offset
89
+ end
90
+
91
+ end
92
+ #end
@@ -0,0 +1,35 @@
1
+ module LocalAssociation
2
+
3
+ extend ActiveSupport::Concern
4
+ include RemoteRelation
5
+
6
+ class_methods do
7
+ def reflection(rel=nil)
8
+ _reflection = self.reflect_on_all_associations.map do |assc|
9
+ { type: assc.class.name[/([^::]+)Reflection\z/,1].underscore,
10
+ klass: (assc.options[:polymorphic] ? nil : assc.klass),
11
+ rel: assc.name,
12
+ foreign_key: assc.foreign_key }
13
+ end
14
+ _reflection += remote_reflections.to_a
15
+ rel.nil? ? _reflection : _reflection.select{|r| r[:rel] == rel }.first
16
+ end
17
+
18
+ def create_callback_for_dependent_destroy_or_nullify rel, opts
19
+ if opts[:dependent] == :destroy
20
+ after_destroy "destroy_#{rel}"
21
+
22
+ define_method "destroy_#{rel}" do
23
+ send(rel).destroy_all
24
+ end
25
+ elsif opts[:dependent] == :nullify
26
+ after_destroy "nullify_#{rel}"
27
+
28
+ define_method "nullify_#{rel}" do
29
+ send(rel).update_all(self.class.foreign_key(rel) => nil)
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,24 @@
1
+ module RemoteAssociation
2
+
3
+ extend ActiveSupport::Concern
4
+ include RemoteRelation
5
+
6
+ class_methods do
7
+
8
+ def belongs_to(rel, opts={})
9
+ remote_belongs_to(rel, opts)
10
+ end
11
+
12
+ def has_one(rel, opts={})
13
+ remote_has_one(rel, opts)
14
+ end
15
+
16
+ def has_many(rel, opts={})
17
+ remote_has_many(rel, opts)
18
+ end
19
+
20
+ def reflection(rel=nil)
21
+ rel.nil? ? remote_reflections : remote_reflections.select{|r| r[:rel] == rel }.first
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,226 @@
1
+ module RemoteRelation
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ Object.const_set(
7
+ "#{self.to_s.split('::').last}Relation", Class.new do
8
+ attr_accessor :xmodel, :params
9
+
10
+ def initialize(xmodel, params={})
11
+ @params = params
12
+ @xmodel = xmodel
13
+ end
14
+
15
+ def find(*ids)
16
+ @params.merge!({ where: [{id: ids.flatten}] })
17
+ resources = all
18
+ (resources.size > 1) ? resources : resources.first
19
+ end
20
+
21
+ def controller_name
22
+ @xmodel.name.pluralize.underscore
23
+ end
24
+
25
+ def destroy_all(where={}, relations={})
26
+ @xmodel.delete(@xmodel.site({ controller: controller_name, action: 'destroy_all' }, @params.delete(:site_options)), { where: [where].flatten }).map{|attrs| @xmodel.new(attrs, false) }
27
+ end
28
+
29
+ def update_all(changes={}, where={}, relations={})
30
+ changes.each do |attrib, value|
31
+ # change true and false by 1 or 0 becouse params are sent as string
32
+ changes[attrib] = (value ? 1 : 0) if !!value == value
33
+ end
34
+ @xmodel.put(@xmodel.site({ controller: controller_name, action: 'update_all' }, @params.delete(:site_options)), { changes: changes, where: [where].flatten }).first
35
+ end
36
+
37
+ def empty_attributes
38
+ @xmodel.get(@xmodel.site({ controller: controller_name, action: 'empty_attributes'}, @params.delete(:site_options))).first
39
+ end
40
+
41
+ def count
42
+ @xmodel.get(@xmodel.site({ controller: controller_name, action: 'count' }, @params.delete(:site_options)), @params).first.to_i
43
+ end
44
+
45
+ def all
46
+ @xmodel.get(@xmodel.site({ controller: controller_name }, @params.delete(:site_options)), @params).map{|attributes| @xmodel.new(attributes, false) }
47
+ end
48
+
49
+ def first
50
+ (@params[:order] ||= []) << { id: :asc }
51
+ @params[:limit] = 1
52
+ all.first
53
+ end
54
+
55
+ def last
56
+ (@params[:order] ||= []) << { id: :desc }
57
+ @params[:limit] = 1
58
+ all.last
59
+ end
60
+
61
+ def joins(*models)
62
+ if @xmodel.same_class?(models)
63
+ params[:joins]= [] unless params.has_key?(:joins)
64
+ tap{ |s| s.params[:joins] += models }
65
+ else
66
+ raise 'Errors: Some class is not Remote Resource'
67
+ end
68
+ end
69
+
70
+ def create(attrs={})
71
+ obj = @xmodel.new(attrs)
72
+ obj.save(@params.delete(:site_options))
73
+ end
74
+
75
+ def where(conditions); tap{|s| (s.params[:where] || s.params[:where] = []) << conditions}; end
76
+
77
+ def order(conditions); tap{|s| (s.params[:order] || s.params[:order] = []) << conditions}; end
78
+
79
+ def limit(number); tap{|s| s.params[:limit] = number }; end
80
+
81
+ def offset(number); tap{|s| s.params[:offset] = number }; end
82
+
83
+ def page(size=1)
84
+ @page = size
85
+ limit(25) unless @params.has_key?(:limit)
86
+ calculate_offset
87
+ end
88
+
89
+ def per(size=25)
90
+ @page ||= 1
91
+ limit(size)
92
+ calculate_offset
93
+ end
94
+
95
+ def calculate_offset; offset(@params[:limit] * (@page - 1)); end
96
+
97
+ def paginate(value={})
98
+ value.has_key?(:page) ? page(value[:page]) : page
99
+ value.has_key?(:per_page) ? per(value[:per_page]) : per
100
+ end
101
+
102
+ def search(params={}); tap{|s| s.params[:search] = params }; end
103
+
104
+ alias_method :ransack, :search
105
+
106
+ def massive_transactions(transaction, method, action)
107
+ @xmodel.send(method, @xmodel.site({ controller: controller_name, action: action }, @params.delete(:site_options)), @params.merge(transaction: transaction))
108
+ end
109
+
110
+ def massive_creation(transaction); massive_transactions(transaction, 'post', 'massive_creation'); end
111
+
112
+ def massive_sum(transaction); massive_transactions(transaction, 'put', 'massive_sum'); end
113
+
114
+ def massive_update(transaction); massive_transactions(transaction, 'put', 'massive_update'); end
115
+
116
+ def method_missing(name, *args, &block)
117
+ all.send(name, *args, &block)
118
+ end
119
+
120
+ end
121
+ )
122
+ end
123
+
124
+ # module ClassMethods
125
+ class_methods do
126
+ @@reflections = {}
127
+
128
+ def same_class?(*relations)
129
+ reflection.select{|r| relations.include?(r[:rel]) }.collect{|r| r[:klass] }.map{|k| k.superclass == self.superclass }.all?
130
+ end
131
+
132
+ # Need implementation in whole relations
133
+ def check_relation(relation)
134
+ (relation - reflection.map{|r| r[:rel] }).empty?
135
+ end
136
+
137
+ def remote_has_many(rel, opts={})
138
+ add_reflection(:has_many, rel, opts)
139
+ self.class_eval do
140
+ define_method rel do
141
+ return polymorphic_has_many(rel, opts) if opts.has_key?(:as)
142
+ if opts.has_key?(:through)
143
+ through_class = opts[:through].to_s.singularize.camelize.constantize
144
+ klass = through_class.xclass(rel)
145
+ through_obj = send(opts[:through])
146
+ through_rel = through_class.reflection(rel)
147
+
148
+ collect_through = (through_rel[:type] == :belong_to) ? through_rel[:foreign_key] : "id"
149
+ foreign_key = (through_rel[:type] == :belong_to) ? "id" : through_rel[:foreign_key]
150
+
151
+ ids = through_obj.is_a?(through_class) ? [through_obj.send(collect_through)] : through_obj.all.collect(&"{collect_through}".to_sym)
152
+
153
+ klass.where(foreign_key => ids)
154
+ else
155
+ self.class.xclass(rel).where(self.class.foreign_key(rel) => self.id)
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ def remote_belongs_to(rel, opts={})
162
+ add_reflection(:belongs_to, rel, opts)
163
+
164
+ self.class_eval do
165
+ define_method rel do
166
+ return polymorphic_belongs_to(rel, opts) if opts.has_key?(:polymorphic)
167
+ class_rel = self.class.xclass(rel)
168
+ foreign_key = self.class.foreign_key(rel)
169
+ send(foreign_key).nil? ? nil : class_rel.find(send(foreign_key))
170
+ end
171
+ end
172
+ end
173
+
174
+ def remote_has_one(rel, opts={})
175
+ add_reflection(:has_one, rel, opts)
176
+ self.class_eval do
177
+ define_method rel do
178
+ return polymorphic_has_one(rel, opts) if opts.has_key?(:as)
179
+
180
+ if opts.has_key?(:through)
181
+ send(opts[:through]).send(rel)
182
+ else
183
+ self.class.xclass(rel).where(self.class.foreign_key(rel) => self.id).first
184
+ end
185
+ end
186
+ end
187
+ end
188
+
189
+ def add_reflection(type, rel, opts)
190
+ return if opts.has_key?(:foreign_key) or opts.has_key?(:polymorphic)
191
+ klass = opts.has_key?(:class_name) ? opts[:class_name].constantize : rel.to_s.singularize.camelize.constantize
192
+ unless opts.has_key?(:through)
193
+ foreign_key = if opts.has_key?(:foreign_key)
194
+ opts[:foreign_key]
195
+ else
196
+ (type == :belongs_to) ? "#{rel.to_s.singularize}_id" : "#{self.to_s.singularize.underscore}_id"
197
+ end
198
+ (@@reflections[self] ||= []) << {type: type, rel: rel, klass: klass, foreign_key: foreign_key}
199
+ end
200
+ end
201
+
202
+ def remote_reflections; @@reflections[self]; end
203
+
204
+
205
+ def foreign_key(rel)
206
+ reflection(rel)[:foreign_key]
207
+ end
208
+
209
+ def xclass(rel)
210
+ reflection(rel)[:klass]
211
+ end
212
+ end
213
+
214
+ def polymorphic_belongs_to(rel, opts={})
215
+ self.send("#{rel}_type").constantize.find(self.send("#{rel}_id"))
216
+ end
217
+
218
+ def polymorphic_has_one(rel, opts={})
219
+ polymorphic_has_many(rel, opts={}).first
220
+ end
221
+
222
+ def polymorphic_has_many(rel, opts={})
223
+ self.class.xclass(rel).where("#{opts[:as]}_id" => self.id, "#{opts[:as]}_type" => self.class.to_s)
224
+ end
225
+
226
+ end
@@ -0,0 +1,35 @@
1
+ module RemoteScope
2
+
3
+ extend ActiveSupport::Concern
4
+ include RemoteRelation
5
+
6
+ class_methods do
7
+
8
+ def node(opts={})
9
+ opts[:identity] = IDENTITY_SITE if not opts.has_key?(:identity) and defined?(IDENTITY_SITE)
10
+ "#{self}Relation".constantize.new(self, { site_options: opts })
11
+ end
12
+
13
+ def build_params keys, values
14
+ hash = Hash[keys.map{|k| [k, values[keys.index(k)]] }]
15
+ hash.empty? ? nil : hash
16
+ end
17
+
18
+ def scope(name, opts={})
19
+ scope_name = opts.has_key?(:remote_scope) ? opts[:remote_scope] : name
20
+
21
+ define_singleton_method name do |*values|
22
+ scope_params = build_params(opts[:using].to_a, values)
23
+ "#{self}Relation".constantize.new(self, { scopes: {scope_name => scope_params} })
24
+ end
25
+
26
+ "#{self}Relation".constantize.class_eval do
27
+ define_method name do |*values|
28
+ scope_params = xmodel.build_params(opts[:using].to_a, values)
29
+ tap{|s| s.params.deep_merge!({ scopes: {scope_name => scope_params} })}
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+ end
data/lib/nube/site.rb ADDED
@@ -0,0 +1,30 @@
1
+ module Site
2
+
3
+ extend ActiveSupport::Concern
4
+
5
+ class_methods do
6
+ def site(*args)
7
+ # Cunado esto esa el BMU el server_id siempre va ser a nil, esto es por que la url esta fixeada en un archivo.
8
+ # ServerConfiguration.find_by_server_id(args.first).site o algo parecido
9
+ # CLOUD_URL + "/api/v1/#{args[0]}"
10
+ host_resource(args) + path_resource + args[0].values.join('/') + default_options(args[1])
11
+ end
12
+
13
+ def host_resource(*args)
14
+ # CLOUD_URL
15
+ "http://0.0.0.0:3002"
16
+ end
17
+
18
+ def path_resource
19
+ '/api/v1/'
20
+ end
21
+
22
+ def default_options(opts={})
23
+ (opts.nil? || opts.empty?) ? '' : ('?' + opts.map{|key,value| "#{key}=#{value}" }.join("&"))
24
+ end
25
+ end
26
+
27
+ def site(*args)
28
+ self.class.site(args)
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module Nube
2
+ VERSION = "0.1.0"
3
+ end
data/lib/nube.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'nube/version'
2
+ require 'nube/site'
3
+ require 'nube/remote_relation'
4
+ require 'nube/remote_scope'
5
+ require 'nube/local_association'
6
+ require 'nube/remote_association'
7
+ require 'nube/controllers/nube_controller'
8
+
9
+ module Nube
10
+ extend ActiveSupport::Autoload
11
+
12
+ autoload :Base
13
+ autoload :Site
14
+ autoload :RemoteRelation
15
+ autoload :RemoteScope
16
+ autoload :LocalAssociation
17
+ autoload :RemoteAssociation
18
+ autoload :NubeController
19
+ end
data/nube.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nube/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "nube"
8
+ spec.version = Nube::VERSION
9
+ spec.authors = ["g.edera", "eserdio"]
10
+ spec.email = ["gab.edera@gmail.com"]
11
+
12
+ spec.summary = %q{It's possible work with object in differents rails aplicacion as activerecord. All relation, scopes, validations for activerecord works with remote objects}
13
+ spec.description = %q{Working with remote objects as activerecord}
14
+ spec.homepage = "https://github.com/gedera/nube.git"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ # end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency('actionpack', '~> 4.x')
31
+ spec.add_dependency('activesupport', '~> 4.x')
32
+ spec.add_dependency('activemodel', '~> 4.x')
33
+ spec.add_dependency("railties", ">= 3.2.6", "< 5")
34
+
35
+ spec.add_development_dependency "bundler", "~> 1.11"
36
+ spec.add_development_dependency "rake", "~> 10.0"
37
+ spec.add_development_dependency "rspec", "~> 3.0"
38
+ end
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nube
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - g.edera
14
+ - eserdio
15
+ autorequire:
16
+ bindir: exe
17
+ cert_chain: []
18
+
19
+ date: 2016-03-10 00:00:00 -03:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: actionpack
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 1938711578
31
+ segments:
32
+ - 4
33
+ - x
34
+ version: 4.x
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: activesupport
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 1938711578
46
+ segments:
47
+ - 4
48
+ - x
49
+ version: 4.x
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: activemodel
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ hash: 1938711578
61
+ segments:
62
+ - 4
63
+ - x
64
+ version: 4.x
65
+ type: :runtime
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: railties
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 3
78
+ - 2
79
+ - 6
80
+ version: 3.2.6
81
+ - - <
82
+ - !ruby/object:Gem::Version
83
+ hash: 9
84
+ segments:
85
+ - 5
86
+ version: "5"
87
+ type: :runtime
88
+ version_requirements: *id004
89
+ - !ruby/object:Gem::Dependency
90
+ name: bundler
91
+ prerelease: false
92
+ requirement: &id005 !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ~>
96
+ - !ruby/object:Gem::Version
97
+ hash: 25
98
+ segments:
99
+ - 1
100
+ - 11
101
+ version: "1.11"
102
+ type: :development
103
+ version_requirements: *id005
104
+ - !ruby/object:Gem::Dependency
105
+ name: rake
106
+ prerelease: false
107
+ requirement: &id006 !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ~>
111
+ - !ruby/object:Gem::Version
112
+ hash: 35
113
+ segments:
114
+ - 10
115
+ - 0
116
+ version: "10.0"
117
+ type: :development
118
+ version_requirements: *id006
119
+ - !ruby/object:Gem::Dependency
120
+ name: rspec
121
+ prerelease: false
122
+ requirement: &id007 !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ~>
126
+ - !ruby/object:Gem::Version
127
+ hash: 7
128
+ segments:
129
+ - 3
130
+ - 0
131
+ version: "3.0"
132
+ type: :development
133
+ version_requirements: *id007
134
+ description: Working with remote objects as activerecord
135
+ email:
136
+ - gab.edera@gmail.com
137
+ executables: []
138
+
139
+ extensions: []
140
+
141
+ extra_rdoc_files: []
142
+
143
+ files:
144
+ - .gitignore
145
+ - .rspec
146
+ - .travis.yml
147
+ - CODE_OF_CONDUCT.md
148
+ - Gemfile
149
+ - LICENSE
150
+ - LICENSE.txt
151
+ - README.md
152
+ - Rakefile
153
+ - bin/console
154
+ - bin/setup
155
+ - lib/nube.rb
156
+ - lib/nube/base.rb
157
+ - lib/nube/controllers/nube_controller.rb
158
+ - lib/nube/local_association.rb
159
+ - lib/nube/remote_association.rb
160
+ - lib/nube/remote_relation.rb
161
+ - lib/nube/remote_scope.rb
162
+ - lib/nube/site.rb
163
+ - lib/nube/version.rb
164
+ - nube.gemspec
165
+ has_rdoc: true
166
+ homepage: https://github.com/gedera/nube.git
167
+ licenses:
168
+ - MIT
169
+ post_install_message:
170
+ rdoc_options: []
171
+
172
+ require_paths:
173
+ - lib
174
+ required_ruby_version: !ruby/object:Gem::Requirement
175
+ none: false
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ hash: 3
180
+ segments:
181
+ - 0
182
+ version: "0"
183
+ required_rubygems_version: !ruby/object:Gem::Requirement
184
+ none: false
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ hash: 3
189
+ segments:
190
+ - 0
191
+ version: "0"
192
+ requirements: []
193
+
194
+ rubyforge_project:
195
+ rubygems_version: 1.6.2
196
+ signing_key:
197
+ specification_version: 3
198
+ summary: It's possible work with object in differents rails aplicacion as activerecord. All relation, scopes, validations for activerecord works with remote objects
199
+ test_files: []
200
+