ooor 1.4.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,145 @@
1
+ # OOOR: Open Object On Rails
2
+ # Copyright (C) 2009-2011 Akretion LTDA (<http://www.akretion.com>).
3
+ # Author: Raphaël Valyi
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ #TODO chainability of where via scopes
19
+ #TODO include relations for single read
20
+
21
+ module Ooor
22
+ # = Similar to Active Record Relation
23
+ class Relation
24
+
25
+ attr_reader :klass, :loaded
26
+ attr_accessor :context, :count_field, :includes_values, :eager_load_values, :preload_values,
27
+ :select_values, :group_values, :order_values, :reorder_flag, :joins_values, :where_values, :having_values,
28
+ :limit_value, :offset_value, :lock_value, :readonly_value, :create_with_value, :from_value
29
+ alias :loaded? :loaded
30
+
31
+ def build_where(opts, other = [])
32
+ case opts
33
+ when Array
34
+ [opts]
35
+ when Hash
36
+ opts.keys.map {|key|["#{key}", "=", opts[key]]}
37
+ end
38
+ end
39
+
40
+ def where(opts, *rest)
41
+ relation = clone
42
+ relation.where_values += build_where(opts, rest) unless opts.blank?
43
+ relation
44
+ end
45
+
46
+ # def having(*args)
47
+ # relation = clone
48
+ # relation.having_values += build_where(*args) unless args.blank?
49
+ # relation
50
+ # end
51
+
52
+ def limit(value)
53
+ relation = clone
54
+ relation.limit_value = value
55
+ relation
56
+ end
57
+
58
+ def offset(value)
59
+ relation = clone
60
+ relation.offset_value = value
61
+ relation
62
+ end
63
+
64
+ def order(*args)
65
+ relation = clone
66
+ relation.order_values += args.flatten unless args.blank?
67
+ relation
68
+ end
69
+
70
+ def count(column_name = nil, options = {})
71
+ column_name, options = nil, column_name if column_name.is_a?(Hash)
72
+ calculate(:count, column_name, options)
73
+ end
74
+
75
+ def initialize(klass)
76
+ @klass = klass
77
+ @where_values = []
78
+ @loaded = false
79
+ @context = {}
80
+ @count_field = false
81
+ @limit_value = false
82
+ @offset_value = false
83
+ @order_values = []
84
+ end
85
+
86
+ def new(*args, &block)
87
+ #TODO inject current domain in *args
88
+ @klass.new(*args, &block)
89
+ end
90
+
91
+ def reload
92
+ reset
93
+ to_a # force reload
94
+ self
95
+ end
96
+
97
+ def initialize_copy(other)
98
+ reset
99
+ end
100
+
101
+ def reset
102
+ @first = @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
103
+ @should_eager_load = @join_dependency = nil
104
+ @records = []
105
+ self
106
+ end
107
+
108
+ # A convenience wrapper for <tt>find(:all, *args)</tt>. You can pass in all the
109
+ # same arguments to this method as you can to <tt>find(:all)</tt>.
110
+ def all(*args)
111
+ #args.any? ? apply_finder_options(args.first).to_a : to_a TODO
112
+ to_a
113
+ end
114
+
115
+ def to_a
116
+ return @records if loaded?
117
+ if @order_values.empty?
118
+ search_order = false
119
+ else
120
+ search_order = @order_values.join(", ")
121
+ end
122
+ ids = @klass.rpc_execute('search', @where_values, @offset_value, @limit_value, search_order, @context, @count_field)
123
+ @records = @klass.find(ids)
124
+ @loaded = true
125
+ @records
126
+ end
127
+
128
+ def eager_loading?
129
+ false
130
+ end
131
+
132
+ protected
133
+
134
+ def method_missing(method, *args, &block)
135
+ if Array.method_defined?(method)
136
+ to_a.send(method, *args, &block)
137
+ elsif @klass.respond_to?(method)
138
+ @klass.send(method, *args, &block)
139
+ else
140
+ @klass.rpc_execute(method.to_s, to_a.map {|record| record.id}, *args)
141
+ end
142
+ end
143
+
144
+ end
145
+ end
@@ -0,0 +1,119 @@
1
+ module Ooor
2
+ module TypeCasting
3
+
4
+ def self.included(base) base.extend(ClassMethods) end
5
+
6
+ module ClassMethods
7
+
8
+ def openerp_string_domain_to_ruby(string_domain)
9
+ eval(string_domain.gsub('(', '[').gsub(')',']'))
10
+ end
11
+
12
+ def to_openerp_domain(domain)
13
+ if domain.is_a?(Hash)
14
+ return domain.map{|k,v| [k.to_s, '=', v]}
15
+ elsif domain == []
16
+ return []
17
+ elsif domain.is_a?(Array) && !domain.last.is_a?(Array)
18
+ return [domain]
19
+ else
20
+ return domain
21
+ end
22
+ end
23
+
24
+ def clean_request_args!(args)
25
+ if args[-1].is_a? Hash
26
+ args[-1] = @ooor.global_context.merge(args[-1])
27
+ elsif args.is_a?(Array)
28
+ args += [@ooor.global_context]
29
+ end
30
+ cast_request_to_openerp!(args[-2]) if args[-2].is_a? Hash
31
+ end
32
+
33
+ def cast_request_to_openerp!(map)
34
+ map.each do |k, v|
35
+ if v == nil
36
+ map[k] = false
37
+ elsif !v.is_a?(Integer) && !v.is_a?(Float) && v.is_a?(Numeric) && v.respond_to?(:to_f)
38
+ map[k] = v.to_f
39
+ elsif !v.is_a?(Numeric) && !v.is_a?(Integer) && v.respond_to?(:sec) && v.respond_to?(:year)#really ensure that's a datetime type
40
+ map[k] = "#{v.year}-#{v.month}-#{v.day} #{v.hour}:#{v.min}:#{v.sec}"
41
+ elsif !v.is_a?(Numeric) && !v.is_a?(Integer) && v.respond_to?(:day) && v.respond_to?(:year)#really ensure that's a date type
42
+ map[k] = "#{v.year}-#{v.month}-#{v.day}"
43
+ end
44
+ end
45
+ end
46
+
47
+ def cast_answer_to_ruby!(answer)
48
+ def cast_map_to_ruby!(map)
49
+ map.each do |k, v|
50
+ if self.fields[k] && v.is_a?(String) && !v.empty?
51
+ case self.fields[k]['type']
52
+ when 'datetime'
53
+ map[k] = Time.parse(v)
54
+ when 'date'
55
+ map[k] = Date.parse(v)
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ if answer.is_a?(Array)
62
+ answer.each {|item| self.cast_map_to_ruby!(item) if item.is_a? Hash}
63
+ elsif answer.is_a?(Hash)
64
+ self.cast_map_to_ruby!(answer)
65
+ else
66
+ answer
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+ def to_openerp_hash!
73
+ cast_relations_to_openerp!
74
+ @attributes.reject {|k, v| k == 'id'}.merge(@associations)
75
+ end
76
+
77
+ def cast_relations_to_openerp!
78
+ @associations.reject! do |k, v| #reject non assigned many2one or empty list
79
+ v.is_a?(Array) && (v.size == 0 or v[1].is_a?(String))
80
+ end
81
+
82
+ def cast_relation(k, v, one2many_associations, many2many_associations)
83
+ if one2many_associations[k]
84
+ return v.collect! do |value|
85
+ if value.is_a?(OpenObjectResource) #on the fly creation as in the GTK client
86
+ [0, 0, value.to_openerp_hash!]
87
+ else
88
+ if value.is_a?(Hash)
89
+ [0, 0, value]
90
+ else
91
+ [1, value, {}]
92
+ end
93
+ end
94
+ end
95
+ elsif many2many_associations[k]
96
+ return v = [[6, 0, v]]
97
+ end
98
+ end
99
+
100
+ @associations.each do |k, v| #see OpenERP awkward associations API
101
+ #already casted, possibly before server error!
102
+ next if (v.is_a?(Array) && v.size == 1 && v[0].is_a?(Array)) \
103
+ || self.class.many2one_associations[k] \
104
+ || !v.is_a?(Array)
105
+ new_rel = self.cast_relation(k, v, self.class.one2many_associations, self.class.many2many_associations)
106
+ if new_rel #matches a known o2m or m2m
107
+ @associations[k] = new_rel
108
+ else
109
+ self.class.many2one_associations.each do |k2, field| #try to cast the association to an inherited o2m or m2m:
110
+ linked_class = self.class.const_get(field['relation'])
111
+ new_rel = self.cast_relation(k, v, linked_class.one2many_associations, linked_class.many2many_associations)
112
+ @associations[k] = new_rel and break if new_rel
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ end
119
+ end
@@ -1,5 +1,5 @@
1
1
  # OOOR: Open Object On Rails
2
- # Copyright (C) 2009-2010 Akretion LTDA (<http://www.akretion.com>).
2
+ # Copyright (C) 2009-2011 Akretion LTDA (<http://www.akretion.com>).
3
3
  # Author: Raphaël Valyi
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
@@ -14,183 +14,206 @@
14
14
  #
15
15
  # You should have received a copy of the GNU Affero General Public License
16
16
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ module Ooor
18
+ module UML
19
+ #usage: UML.print_uml or with options: UML.print_uml(:all, :detailed) or MyOpenObjectResource.print_uml or UML.print_uml([list_of_classes], :all, :detailed)
17
20
 
18
- module UML
19
- #usage: UML.print_uml or with options: UML.print_uml(:all, : detailed) or MyOpenObjectResource.print_uml or UML.print_uml([list_of_classes], :all, :detailed)
21
+ def self.included(base) base.extend(ClassMethods) end
20
22
 
21
- def self.included(base) base.extend(ClassMethods) end
22
-
23
- def print_uml(*options)
24
- ooor = self.class.ooor
25
- UML.print_uml(ooor.config[:models] && ooor.loaded_models.select {|model| ooor.config[:models].index(model.openerp_model)} || ooor.loaded_models, options)
26
- end
27
-
28
- module ClassMethods
29
23
  def print_uml(*options)
30
- UML.print_uml([self], options)
24
+ ooor = self.class.ooor
25
+ UML.print_uml(ooor.config[:models] && ooor.loaded_models.select {|model| ooor.config[:models].index(model.openerp_model)} || ooor.loaded_models, options)
31
26
  end
32
- end
33
-
34
- def self.display_fields(clazz)
35
- s = ""
36
- clazz.reload_fields_definition if clazz.fields.empty?
37
- clazz.fields.sort {|a,b| a[1]['type'] <=> b[1]['type']}.each {|i| s << "+ #{i[1]['type']} : #{i[0]}\\l\\n"}
38
- s
39
- end
40
-
41
- def self.print_uml(classes, *options)
42
- options = options[0] if options[0].is_a?(Array)
43
- local = (options.index(:all) == nil)
44
- detailed = (options.index(:detailed) != nil) || local && (options.index(:nodetail) == nil)
45
-
46
- enabled_targets = classes[0].ooor.config[:models] #defines the scope of the UML for option local
47
- m2o_edges = {}
48
- o2m_edges = {}
49
- m2m_edges = {}
50
- #instead of diplaying several relations of the same kind between two nodes which would bloat the graph,
51
- #we track them all and factor them on a common multiline edge label:
52
- connex_classes = UML.collect_edges(false, local, classes, enabled_targets, m2o_edges, o2m_edges, m2m_edges)
53
- #back links from connex classes:
54
- connex_classes += UML.collect_edges(true, local, connex_classes - classes, classes, m2o_edges, o2m_edges, m2m_edges)
55
-
56
- File.open('uml.dot', 'w') do |f|
57
- f << <<-eos
58
- digraph G {
59
- fontname = "Bitstream Vera Sans"
60
- fontsize = 8
61
- label = "*** generated by OOOR by www.akretion.com ***"
62
- node [
63
- fontname = "Bitstream Vera Sans"
64
- fontsize = 16
65
- shape = "record"
66
- fillcolor=orange
67
- style="rounded,filled"
68
- ]
69
- edge [
70
- arrowhead = "none"
71
- fontname = "Bitstream Vera Sans"
72
- fontsize = 9
73
- ]
74
- eos
75
-
76
- #UML nodes definitions
77
- ((connex_classes - classes) + classes - [IrModel, IrModelFields]).each do |model|
78
- f << " #{model} [ label = \"{#{model.name}#{detailed ? '|' + display_fields(model) : ''}}\" ]"
79
- end
80
27
 
81
- #many2one:
82
- f << <<-eos
83
- edge [
84
- headlabel = "1"
85
- taillabel = "n"
86
- ]
87
- eos
88
- m2o_edges.each do |k, v|
89
- reverse_part = v[3].size > 0 ? "\\n/#{v[3].join("\\n")}\"]\n" : "\"]\n"
90
- f << "edge [label = \"#{v[2].join("\\n")}#{reverse_part}"
91
- f << "#{v[0]} -> #{v[1]}\n"
28
+ def serve_uml(*options)#TODO port
29
+ ooor = self
30
+ require 'sinatra'
31
+ set :public, File.dirname(__FILE__) + '/../../'
32
+
33
+ get '/model/:model_name' do
34
+ model_name = params[:model_name]
35
+ model = ooor.const_get(model_name)
36
+ model.print_uml
37
+ s = ""#"Hello world! #{model_name}"
38
+ s << "<IMG SRC='/x.png' USEMAP='#UMLbyOOOR' />"
39
+ f=File.open('x.map')
40
+ f.each_line {|l| s << l}
41
+ s
92
42
  end
93
43
 
94
- #one2many:
95
- f << <<-eos
96
- edge [
97
- headlabel = "n"
98
- taillabel = "1"
99
- ]
100
- eos
101
- o2m_edges.each do |k, v|
102
- f << "edge [label = \"#{v[3].join("\\n")}\"]\n"
103
- f << "#{v[0]} -> #{v[1]}\n"
104
- end
44
+ Sinatra::Application.run!
45
+ end
105
46
 
106
- #many2many:
107
- f << <<-eos
108
- edge [
109
- headlabel = "n"
110
- taillabel = "n"
111
- ]
112
- eos
113
- m2m_edges.each do |k, v|
114
- reverse_part = v[3].size > 0 ? "\\n/#{v[3].join("\\n")}\"]\n" : "\"]\n"
115
- f << "edge [label = \"#{v[2].join("\\n")}}#{reverse_part}"
116
- f << "#{v[0]} -> #{v[1]}\n"
47
+ module ClassMethods
48
+ def print_uml(*options)
49
+ UML.print_uml([self], options)
117
50
  end
118
-
119
- f << "}"
120
51
  end
121
52
 
122
- begin
123
- cmd_line1 = "rm uml.png"
124
- system(cmd_line1)
125
- rescue
53
+ def self.display_fields(clazz)
54
+ s = ""
55
+ clazz.reload_fields_definition if clazz.fields.empty?
56
+ #clazz.fields.sort {|a,b| a[1]['type'] <=> b[1]['type']}.each {|i| s << "+ #{i[1]['type']} : #{i[0]}\\l\\n"}
57
+ clazz.fields.sort {|a,b| a[1]['type'] <=> b[1]['type']}.each {|i| s << "<TR><TD COLSPAN=\"2\" BGCOLOR=\"#bed1b8\" ALIGN=\"LEFT\">#{i[0]}</TD><TD ALIGN=\"LEFT\">#{i[1]['type']}</TD></TR>\\l\\n"}
58
+ s
126
59
  end
127
- cmd_line2 = "dot -Tpng uml.dot -o uml.png"
128
- system(cmd_line2)
129
- end
130
60
 
131
- def self.collect_edges(is_reverse, local, classes, enabled_targets, m2o_edges, o2m_edges, m2m_edges)
132
- connex_classes = Set.new
133
-
134
- classes.each do |model|
135
- model.reload_fields_definition if model.fields.empty?
136
-
137
- #many2one:
138
- model.many2one_relations.each do |k, field|
139
- target = UML.get_target(is_reverse, local, enabled_targets, field, model)
140
- if target
141
- connex_classes.add(target)
142
- if m2o_edges["#{model}-#{target}"]
143
- m2o_edges["#{model}-#{target}"][2] += [k]
144
- else
145
- m2o_edges["#{model}-#{target}"] = [model, target, [k], []]
146
- end
61
+ def self.print_uml(classes, *options)
62
+ options = options[0] if options[0].is_a?(Array)
63
+ local = (options.index(:all) == nil)
64
+ detailed = (options.index(:detailed) != nil) || local && (options.index(:nodetail) == nil)
65
+
66
+ enabled_targets = classes[0].ooor.config[:models] #defines the scope of the UML for option local
67
+ m2o_edges = {}
68
+ o2m_edges = {}
69
+ m2m_edges = {}
70
+ #instead of diplaying several relations of the same kind between two nodes which would bloat the graph,
71
+ #we track them all and factor them on a common multiline edge label:
72
+ connex_classes = UML.collect_edges(false, local, classes, enabled_targets, m2o_edges, o2m_edges, m2m_edges)
73
+ #back links from connex classes:
74
+ connex_classes += UML.collect_edges(true, local, connex_classes - classes, classes, m2o_edges, o2m_edges, m2m_edges)
75
+
76
+ File.open('uml.dot', 'w') do |f|
77
+ f << <<-eos
78
+ digraph UMLbyOOOR {
79
+ fontname = "Helvetica"
80
+ fontsize = 11
81
+ label = "*** generated by OOOR by www.akretion.com ***"
82
+ node [
83
+ fontname = "Helvetica"
84
+ fontsize = 11
85
+ shape = "record"
86
+ fillcolor=orange
87
+ style="rounded,filled"
88
+ ]
89
+ edge [
90
+ arrowhead = "none"
91
+ fontname = "Helvetica"
92
+ fontsize = 9
93
+ ]
94
+ eos
95
+
96
+ #UML nodes definitions
97
+ ((connex_classes - classes) + classes - [IrModel, IrModel.const_get('ir.model.fields')]).each do |model|
98
+ #f << " #{model} [ label = \"{#{model.name}#{detailed ? '|' + display_fields(model) : ''}}\" URL=\"/model/#{model.openerp_model}\"];\n"
99
+ f << "#{model}[label=<<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" BGCOLOR=\"#ffffff\"><TR><TD COLSPAN=\"3\" BGCOLOR=\"#9bab96\" ALIGN=\"CENTER\">#{model.name}</TD></TR>#{display_fields(model)}</TABLE>> URL=\"/model/#{model.openerp_model}\"];\n"
100
+ end
101
+
102
+ #many2one:
103
+ f << <<-eos
104
+ edge [
105
+ headlabel = "1"
106
+ taillabel = "n"
107
+ ]
108
+ eos
109
+ m2o_edges.each do |k, v|
110
+ reverse_part = v[3].size > 0 ? "\\n/#{v[3].join("\\n")}\"]\n" : "\"]\n"
111
+ f << "edge [label = \"#{v[2].join("\\n")}#{reverse_part}"
112
+ f << "#{v[0]} -> #{v[1]}\n"
147
113
  end
148
114
 
115
+ #one2many:
116
+ f << <<-eos
117
+ edge [
118
+ headlabel = "n"
119
+ taillabel = "1"
120
+ ]
121
+ eos
122
+ o2m_edges.each do |k, v|
123
+ f << "edge [label = \"#{v[3].join("\\n")}\"]\n"
124
+ f << "#{v[0]} -> #{v[1]}\n"
125
+ end
126
+
127
+ #many2many:
128
+ f << <<-eos
129
+ edge [
130
+ headlabel = "n"
131
+ taillabel = "n"
132
+ ]
133
+ eos
134
+ m2m_edges.each do |k, v|
135
+ reverse_part = v[3].size > 0 ? "\\n/#{v[3].join("\\n")}\"]\n" : "\"]\n"
136
+ f << "edge [label = \"#{v[2].join("\\n")}}#{reverse_part}"
137
+ f << "#{v[0]} -> #{v[1]}\n"
138
+ end
139
+
140
+ f << "}"
149
141
  end
142
+
143
+ begin
144
+ cmd_line1 = "rm uml.png"
145
+ #system(cmd_line1)
146
+ rescue
147
+ end
148
+ #cmd_line2 = "dot -Tpng uml.dot -o uml.png"
149
+ cmd_line2 = "dot -Tcmapx -ox.map -Tpng -ox.png uml.dot"
150
+ system(cmd_line2)
150
151
  end
151
152
 
152
- classes.each do |model|
153
- #one2many:
154
- model.one2many_relations.each do |k, field|
155
- target = UML.get_target(is_reverse, local, enabled_targets, field, model)
156
- if target
157
- connex_classes.add(target)
158
- if m2o_edges["#{target}-#{model}"]
159
- m2o_edges["#{target}-#{model}"][3] += [k]
160
- elsif o2m_edges["#{model}-#{target}"]
161
- o2m_edges["#{model}-#{target}"][3] += [k]
162
- else
163
- o2m_edges["#{model}-#{target}"] = [model, target, [], [k]]
153
+ def self.collect_edges(is_reverse, local, classes, enabled_targets, m2o_edges, o2m_edges, m2m_edges)
154
+ connex_classes = Set.new
155
+
156
+ classes.each do |model|
157
+ model.reload_fields_definition if model.fields.empty?
158
+
159
+ #many2one:
160
+ model.many2one_associations.each do |k, field|
161
+ target = UML.get_target(is_reverse, local, enabled_targets, field, model)
162
+ if target
163
+ connex_classes.add(target)
164
+ if m2o_edges["#{model}-#{target}"]
165
+ m2o_edges["#{model}-#{target}"][2] += [k]
166
+ else
167
+ m2o_edges["#{model}-#{target}"] = [model, target, [k], []]
168
+ end
164
169
  end
170
+
165
171
  end
166
172
  end
167
173
 
168
- #many2many:
169
- model.many2many_relations.each do |k, field|
170
- target = UML.get_target(is_reverse, local, enabled_targets, field, model)
171
- if target
172
- connex_classes.add(target)
173
- if m2m_edges["#{model}-#{target}"]
174
- m2m_edges["#{model}-#{target}"][2] += [k]
175
- elsif m2m_edges["#{target}-#{model}"]
176
- m2m_edges["#{target}-#{model}"][3] += [k]
177
- else
178
- m2m_edges["#{model}-#{target}"] = [model, target, [k], []]
174
+ classes.each do |model|
175
+ #one2many:
176
+ model.one2many_associations.each do |k, field|
177
+ target = UML.get_target(is_reverse, local, enabled_targets, field, model)
178
+ if target
179
+ connex_classes.add(target)
180
+ if m2o_edges["#{target}-#{model}"]
181
+ m2o_edges["#{target}-#{model}"][3] += [k]
182
+ elsif o2m_edges["#{model}-#{target}"]
183
+ o2m_edges["#{model}-#{target}"][3] += [k]
184
+ else
185
+ o2m_edges["#{model}-#{target}"] = [model, target, [], [k]]
186
+ end
187
+ end
188
+ end
189
+
190
+ #many2many:
191
+ model.many2many_associations.each do |k, field|
192
+ target = UML.get_target(is_reverse, local, enabled_targets, field, model)
193
+ if target
194
+ connex_classes.add(target)
195
+ if m2m_edges["#{model}-#{target}"]
196
+ m2m_edges["#{model}-#{target}"][2] += [k]
197
+ elsif m2m_edges["#{target}-#{model}"]
198
+ m2m_edges["#{target}-#{model}"][3] += [k]
199
+ else
200
+ m2m_edges["#{model}-#{target}"] = [model, target, [k], []]
201
+ end
179
202
  end
180
203
  end
181
- end
182
204
 
205
+ end
206
+ connex_classes
183
207
  end
184
- connex_classes
185
- end
186
208
 
187
- private
209
+ private
188
210
 
189
- def self.get_target(is_reverse, local, enabled_targets, field, model)
190
- if (is_reverse && !local) || (!enabled_targets) || enabled_targets.index(field['relation'])
191
- model.const_get(field['relation'])
192
- else
193
- false
211
+ def self.get_target(is_reverse, local, enabled_targets, field, model)
212
+ if (is_reverse && !local) || (!enabled_targets) || enabled_targets.index(field['relation'])
213
+ model.const_get(field['relation'])
214
+ else
215
+ false
216
+ end
194
217
  end
195
218
  end
196
219
  end