qooxview 1.9.10 → 1.9.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/Gemfile.lock +43 -35
- data/bin/test_ldap.rb +90 -0
- data/lib/qooxview.rb +11 -3
- data/lib/qooxview/additions.rb +1 -13
- data/lib/qooxview/config_yaml.rb +55 -5
- data/lib/qooxview/entity.rb +16 -21
- data/lib/qooxview/frontend/build/index.html +2 -2
- data/lib/qooxview/frontend/build/script/frontend.js +2 -2
- data/lib/qooxview/frontend/build/source +1 -0
- data/lib/qooxview/frontend/source/UploadMgr +1 -0
- data/lib/qooxview/frontend/source/class/frontend/Lib/RPC.js +1 -1
- data/lib/qooxview/frontend/source/index.html +1 -1
- data/lib/qooxview/frontend/source/source +1 -0
- data/lib/qooxview/helpers/config_base.rb +2 -4
- data/lib/qooxview/helpers/open_print.rb +2 -1
- data/lib/qooxview/qooxview.rb +24 -11
- data/lib/qooxview/rpcqooxdoo.rb +7 -6
- data/lib/qooxview/storage_handler.rb +61 -20
- data/lib/qooxview/storages/csv.rb +7 -6
- data/lib/qooxview/storages/ldap.rb +14 -6
- data/lib/qooxview/storages/sqlite.rb +25 -7
- data/lib/qooxview/view.rb +6 -0
- data/qooxview.gemspec +11 -11
- data/test/benchmark_creation.rb +1 -1
- data/test/entities/init_test.rb +13 -0
- data/test/qv_config.rb +65 -0
- data/test/qv_entity.rb +19 -1
- data/test/qv_helpers.rb +1 -1
- data/test/qv_view.rb +1 -1
- data/test/test.conf +1 -0
- data/test/test.rb +2 -2
- metadata +35 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c23748472d694e11be55e85c959055bd08158c5
|
4
|
+
data.tar.gz: 24f715cfadda8ffc48cc41f81b6e05b5890164cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a76c27f533696e75d974f9b8655c1115bea68c5c485867b75785cc0fbc0702b9366573dc043d9020223fba5f7f853220bcfc789aa82ba5868dceb9430845c971
|
7
|
+
data.tar.gz: 49d5c59baa85e88e0f55115517f8c19893ec3db8605b42bd14e6c55bae4124e2af0737d6381e416b8f507c464d015b3661da506fe0cc92414d79aa9846f95c13
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.1
|
1
|
+
2.4.1
|
data/Gemfile.lock
CHANGED
@@ -1,79 +1,87 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../HelperClasses
|
3
|
+
specs:
|
4
|
+
helper_classes (0.3.5)
|
5
|
+
|
1
6
|
PATH
|
2
7
|
remote: .
|
3
8
|
specs:
|
4
|
-
qooxview (1.9.
|
5
|
-
activemodel (=
|
6
|
-
activerecord (=
|
7
|
-
activesupport (=
|
8
|
-
arel (=
|
9
|
+
qooxview (1.9.11)
|
10
|
+
activemodel (= 5.1.0)
|
11
|
+
activerecord (= 5.1.0)
|
12
|
+
activesupport (= 5.1.0)
|
13
|
+
arel (= 8.0)
|
9
14
|
chunky_png (= 1.3.4)
|
10
15
|
docsplit (= 0.7.6)
|
11
16
|
gettext (= 3.0.0)
|
12
|
-
helper_classes (= 0.3.
|
13
|
-
i18n (= 0.
|
17
|
+
helper_classes (= 0.3.5)
|
18
|
+
i18n (= 0.7.0)
|
14
19
|
iconv (= 1.0.3)
|
15
20
|
iniparse (= 1.4.0)
|
16
|
-
json (= 1.
|
21
|
+
json (= 2.1.0)
|
17
22
|
locale (= 2.0.8)
|
18
23
|
multi_json (= 1.0.3)
|
19
|
-
net-ldap (= 0.
|
24
|
+
net-ldap (= 0.16)
|
20
25
|
rqrcode (= 0.4.2)
|
21
26
|
rqrcode-with-patches (= 0.5.4)
|
22
27
|
rubyzip (= 1.1.7)
|
23
28
|
serialport (= 1.3.1)
|
24
29
|
sqlite3 (= 1.3.10)
|
30
|
+
test-unit (= 3.2.3)
|
25
31
|
text (= 1.2.3)
|
26
32
|
|
27
|
-
PATH
|
28
|
-
remote: vendor/cache/HelperClasses
|
29
|
-
specs:
|
30
|
-
helper_classes (0.3.2)
|
31
|
-
|
32
33
|
GEM
|
33
34
|
remote: https://rubygems.org/
|
34
35
|
specs:
|
35
|
-
activemodel (
|
36
|
-
activesupport (=
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
arel (
|
47
|
-
builder (3.0.4)
|
36
|
+
activemodel (5.1.0)
|
37
|
+
activesupport (= 5.1.0)
|
38
|
+
activerecord (5.1.0)
|
39
|
+
activemodel (= 5.1.0)
|
40
|
+
activesupport (= 5.1.0)
|
41
|
+
arel (~> 8.0)
|
42
|
+
activesupport (5.1.0)
|
43
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
44
|
+
i18n (~> 0.7)
|
45
|
+
minitest (~> 5.1)
|
46
|
+
tzinfo (~> 1.1)
|
47
|
+
arel (8.0.0)
|
48
48
|
chunky_png (1.3.4)
|
49
|
+
concurrent-ruby (1.0.5)
|
49
50
|
docsplit (0.7.6)
|
50
51
|
gettext (3.0.0)
|
51
52
|
locale (>= 2.0.5)
|
52
53
|
text
|
53
|
-
i18n (0.
|
54
|
+
i18n (0.7.0)
|
54
55
|
iconv (1.0.3)
|
55
56
|
iniparse (1.4.0)
|
56
|
-
json (1.
|
57
|
+
json (2.1.0)
|
57
58
|
locale (2.0.8)
|
59
|
+
minitest (5.10.2)
|
58
60
|
multi_json (1.0.3)
|
59
|
-
net-ldap (0.
|
60
|
-
|
61
|
-
rake (10.
|
61
|
+
net-ldap (0.16.0)
|
62
|
+
power_assert (1.0.2)
|
63
|
+
rake (10.5.0)
|
62
64
|
rqrcode (0.4.2)
|
63
65
|
rqrcode-with-patches (0.5.4)
|
64
66
|
chunky_png
|
65
67
|
rubyzip (1.1.7)
|
66
68
|
serialport (1.3.1)
|
67
69
|
sqlite3 (1.3.10)
|
70
|
+
test-unit (3.2.3)
|
71
|
+
power_assert
|
68
72
|
text (1.2.3)
|
69
|
-
|
73
|
+
thread_safe (0.3.6)
|
74
|
+
tzinfo (1.2.3)
|
75
|
+
thread_safe (~> 0.1)
|
70
76
|
|
71
77
|
PLATFORMS
|
72
78
|
ruby
|
73
79
|
|
74
80
|
DEPENDENCIES
|
75
|
-
bundler (~> 1.
|
81
|
+
bundler (~> 1.14)
|
76
82
|
helper_classes!
|
77
|
-
perftools.rb (= 2.0.1)
|
78
83
|
qooxview!
|
79
84
|
rake (~> 10.0)
|
85
|
+
|
86
|
+
BUNDLED WITH
|
87
|
+
1.14.6
|
data/bin/test_ldap.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
Encoding.default_external = Encoding::UTF_8
|
5
|
+
|
6
|
+
require 'bundler/setup'
|
7
|
+
require 'iniparse'
|
8
|
+
require 'helper_classes/dputs'
|
9
|
+
require 'net/ldap'
|
10
|
+
|
11
|
+
include HelperClasses::DPuts
|
12
|
+
|
13
|
+
DEBUG_LVL=4
|
14
|
+
|
15
|
+
def get_param(lc, param)
|
16
|
+
lc['__anonymous__'][param].delete('"\'')
|
17
|
+
end
|
18
|
+
|
19
|
+
file_conf = '/etc/ldapscripts/ldapscripts.conf'
|
20
|
+
ldap_config = IniParse.parse(File.read(file_conf))
|
21
|
+
dputs(2) { "Configuration options are #{ldap_config.to_hash.inspect}" }
|
22
|
+
@data_ldap_host, @data_ldap_base, @data_ldap_root, @data_ldap_users =
|
23
|
+
get_param(ldap_config, 'SERVER'), get_param(ldap_config, 'SUFFIX'),
|
24
|
+
get_param(ldap_config, 'BINDDN'), get_param(ldap_config, 'USUFFIX')
|
25
|
+
|
26
|
+
file_pass = '/etc/ldap.secret'
|
27
|
+
@data_ldap_pass = `cat #{ file_pass }`
|
28
|
+
@data_ldap_users += ",#{@data_ldap_base}"
|
29
|
+
%w( host base root pass users ).each { |v| eval("dputs( 3 ){ @data_ldap_#{v}.to_s}") }
|
30
|
+
|
31
|
+
@data_ldap = Net::LDAP.new :host => @data_ldap_host,
|
32
|
+
:auth => {
|
33
|
+
:method => :simple,
|
34
|
+
:username => @data_ldap_root,
|
35
|
+
:password => @data_ldap_pass
|
36
|
+
}
|
37
|
+
|
38
|
+
# Read in the entries from the LDAP-directory
|
39
|
+
dputs(3) { 'Reading LDAP-entries' }
|
40
|
+
filter = Net::LDAP::Filter.eq('cn', '*')
|
41
|
+
@field_id_ldap = :uidNumber
|
42
|
+
|
43
|
+
case 1
|
44
|
+
when 0 # Read all entries
|
45
|
+
dputs(3) { "Going to read #{@data_ldap_base}" }
|
46
|
+
@data_ldap.search(:base => @data_ldap_base, :filter => filter) do |entry|
|
47
|
+
dputs(4) { "DN: #{entry.dn}" }
|
48
|
+
end
|
49
|
+
when 1 # Write to one entry
|
50
|
+
filter = Net::LDAP::Filter.eq('uid', 'ltest3')
|
51
|
+
dn, uidnumber = 0, 0
|
52
|
+
@data_ldap.search(:base => @data_ldap_base, :filter => filter) do |entry|
|
53
|
+
dputs(3) { "DN: #{entry.dn} - uidn: #{entry.uidnumber} - entry: #{entry}" }
|
54
|
+
dn = entry.dn
|
55
|
+
uidnumber = entry.uidnumber.first
|
56
|
+
end
|
57
|
+
dp dn
|
58
|
+
dp uidnumber
|
59
|
+
value_stored = 'test'
|
60
|
+
attribute = 'sn'
|
61
|
+
dputs(3) { 'Replacing attribute in ' +
|
62
|
+
"#{[@data_ldap_pass, dn, uidnumber, attribute, value_stored].inspect}" }
|
63
|
+
|
64
|
+
if not dn
|
65
|
+
dputs(0) { "Error: DN is empty... #{@dns.to_a.last(10).inspect}" }
|
66
|
+
dputs(0) { "Error: DN is empty: id, field, value = #{id}, #{field}, #{value}" }
|
67
|
+
#return
|
68
|
+
end
|
69
|
+
|
70
|
+
ret = @data_ldap.replace_attribute(dn, attribute, value_stored.to_s)
|
71
|
+
#ret = @data_ldap.add_attribute(dn, attribute, value_stored.to_s)
|
72
|
+
#ret = @data_ldap.replace_attribute(dn, 'objectClass', %w( inetOrgPerson posixAccount ))
|
73
|
+
dp ret
|
74
|
+
puts "Result: #{@data_ldap.get_operation_result.code}"
|
75
|
+
puts "Message: #{@data_ldap.get_operation_result.message}"
|
76
|
+
|
77
|
+
|
78
|
+
filter2 = Net::LDAP::Filter.eq(@field_id_ldap.to_s, uidnumber.to_s)
|
79
|
+
@data_ldap.search(:base => @data_ldap_base,
|
80
|
+
:filter => filter2) do |entry|
|
81
|
+
dputs(3) { "Found entry: #{entry.inspect}" }
|
82
|
+
value_entry = entry[attribute][0].to_s
|
83
|
+
value_entry.force_encoding(Encoding::UTF_8)
|
84
|
+
if value_stored.to_s == value_entry
|
85
|
+
dputs(0) { "returning value #{value_stored.inspect}" }
|
86
|
+
else
|
87
|
+
dputs(0) { "Error: Didn't get right return value: #{value_entry.inspect} instead of #{value_stored.inspect}" }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/qooxview.rb
CHANGED
@@ -39,10 +39,10 @@ show_info :welcome, "hello world"
|
|
39
39
|
show_button :welt, :world
|
40
40
|
end
|
41
41
|
def rpc_button_welt( session, args* )
|
42
|
-
reply(
|
42
|
+
reply( :update, welcome: "Hallo Welt" )
|
43
43
|
end
|
44
44
|
def rpc_button_world( session, args* )
|
45
|
-
reply(
|
45
|
+
reply( :update, welcome: "Hello world" )
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -75,7 +75,15 @@ of both:
|
|
75
75
|
|
76
76
|
=== Configuration-file
|
77
77
|
|
78
|
-
|
78
|
+
There are two configuration-files:
|
79
|
+
- $name.conf - which holds general configurations like data-directory
|
80
|
+
- bash-style configuration, as it is also used by scripts
|
81
|
+
- this file is searched upwards from the $name.rb, then in /etc, if not found.
|
82
|
+
Deafault values used when not found:
|
83
|
+
- DATA_DIR=/var/lib/$name
|
84
|
+
- config.yaml - application-specific configuration that is not used by scripts
|
85
|
+
- this file is searched in the DATA_DIR
|
86
|
+
- if not present, will be copied into DATA_DIR
|
79
87
|
|
80
88
|
=end
|
81
89
|
|
data/lib/qooxview/additions.rb
CHANGED
@@ -136,19 +136,7 @@ class Date
|
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
139
|
-
class
|
140
|
-
def separator(sep = ' ')
|
141
|
-
self.to_s.tap do |s|
|
142
|
-
:go while s.gsub!(/^([^.]*)(\d)(?=(\d{3})+)/, "\\1\\2#{sep}")
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
def to_MB(label = 'MB')
|
147
|
-
"#{(self / 1_000_000).separator} #{label}"
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
class Bignum
|
139
|
+
class Integer
|
152
140
|
def separator(sep = ' ')
|
153
141
|
self.to_s.tap do |s|
|
154
142
|
:go while s.gsub!(/^([^.]*)(\d)(?=(\d{3})+)/, "\\1\\2#{sep}")
|
data/lib/qooxview/config_yaml.rb
CHANGED
@@ -1,8 +1,57 @@
|
|
1
|
-
$config
|
2
|
-
|
3
|
-
|
1
|
+
$config ||= {}
|
2
|
+
$name = $0.match(/.*?([^\/]*?)(.rb)*$/)[1]
|
3
|
+
|
4
|
+
# Searches for name in every directory from 'dir' towards the root and
|
5
|
+
# returns the found filename.
|
6
|
+
# If nothing is found, it returns nil
|
7
|
+
# If 'dir' is nil, the directory of the running script is taken
|
8
|
+
def search_up(name, dir = nil)
|
9
|
+
dir ||= File.realdirpath(File.dirname($0))
|
10
|
+
dputs(3){"Directory is #{dir}, searching #{name}"}
|
11
|
+
return File.join(dir, name) if File.exists?(File.join(dir, name))
|
12
|
+
return nil if File.realdirpath(dir) == '/'
|
13
|
+
search_up(name, File.realdirpath(File.join(dir, '..')))
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_config_global(path=nil)
|
17
|
+
#dputs_func
|
18
|
+
if conf = search_up("#{$name.downcase}.conf", path)
|
19
|
+
dputs(3) { "Found configuration-file #{conf}" }
|
20
|
+
IO.readlines(conf).each { |l|
|
21
|
+
dputs(4) { "Reading line #{l}" }
|
22
|
+
next if l =~ /(^#|^\s*$)/
|
23
|
+
name, value =
|
24
|
+
case l
|
25
|
+
when /^\s*(.*?)="(.*?)".*$/
|
26
|
+
[$1, $2]
|
27
|
+
when /^\s*(.*?)=([^\s#]*)/
|
28
|
+
[$1, $2]
|
29
|
+
else
|
30
|
+
[nil, nil]
|
31
|
+
end
|
32
|
+
if name && value
|
33
|
+
dputs(3) { "Writing configuration _#{$1}_ = _#{$2}_" }
|
34
|
+
$config[$1.to_sym] = $2
|
35
|
+
end
|
36
|
+
}
|
37
|
+
end
|
38
|
+
unless defined?($data_dir)
|
39
|
+
$data_dir = $config[:DATA_DIR] || "/var/lib/#{$name.downcase}"
|
40
|
+
FileUtils.mkdir_p($data_dir)
|
41
|
+
end
|
42
|
+
unless defined?($config_file)
|
43
|
+
$config_file = File.join($data_dir, 'config.yaml')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_config_yaml(path = nil)
|
48
|
+
if defined?($config_file)
|
49
|
+
file = path ? File.join(path, $config_file) : $config_file
|
50
|
+
if FileTest.exist?(file)
|
51
|
+
File.open(file) { |f| $config.merge!(YAML::load(f).to_sym) }
|
52
|
+
end
|
53
|
+
end
|
4
54
|
end
|
5
|
-
$name = $0.match(/.*?([^\/]*).rb/)[1]
|
6
55
|
|
7
56
|
def get_config(default, *path)
|
8
57
|
get_config_rec(path, default)
|
@@ -39,4 +88,5 @@ def set_config(value, *path)
|
|
39
88
|
end
|
40
89
|
end
|
41
90
|
|
42
|
-
|
91
|
+
load_config_global
|
92
|
+
load_config_yaml
|
data/lib/qooxview/entity.rb
CHANGED
@@ -43,6 +43,7 @@ class Entities < RPCQooxdooService
|
|
43
43
|
@null_allowed = false
|
44
44
|
@loading = false
|
45
45
|
@is_loaded = false
|
46
|
+
@dont_migrate = false
|
46
47
|
|
47
48
|
if @data_class != 'Entity'
|
48
49
|
@@all[@data_class] = self
|
@@ -84,6 +85,11 @@ class Entities < RPCQooxdooService
|
|
84
85
|
end
|
85
86
|
end
|
86
87
|
|
88
|
+
# Overwrites ActiveSupport load, which is not needed
|
89
|
+
def self.load(has_static = true)
|
90
|
+
Entities.method_missing(self.name).load(has_static)
|
91
|
+
end
|
92
|
+
|
87
93
|
# Here comes the definition of the data used in that Entity. If the
|
88
94
|
# return-value is true, the data is loaded automatically
|
89
95
|
def setup_data
|
@@ -167,9 +173,9 @@ class Entities < RPCQooxdooService
|
|
167
173
|
# instantiated - useful for stuff like long LDAP-lists...
|
168
174
|
def get_data_instance(k)
|
169
175
|
return nil if !k
|
170
|
-
if k.class !=
|
176
|
+
if k.class != Integer
|
171
177
|
dputs(0) { 'This is very bad' }
|
172
|
-
dputs(0) { "value k is #{k.inspect}" }
|
178
|
+
dputs(0) { "value k is #{k.inspect} - #{k.class}" }
|
173
179
|
dputs(0) { "caller-stack is #{caller}" }
|
174
180
|
raise 'WrongIndex'
|
175
181
|
end
|
@@ -246,12 +252,12 @@ class Entities < RPCQooxdooService
|
|
246
252
|
end
|
247
253
|
end
|
248
254
|
|
249
|
-
def respond_to?(cmd)
|
255
|
+
def respond_to?(cmd, all = false)
|
250
256
|
dputs(5) { cmd.inspect }
|
251
257
|
if cmd =~ /^(match_by_|search_by_|list_|listp_|value_)/
|
252
258
|
return true
|
253
259
|
end
|
254
|
-
super cmd
|
260
|
+
super cmd, all
|
255
261
|
end
|
256
262
|
|
257
263
|
def whoami
|
@@ -344,7 +350,7 @@ class Entities < RPCQooxdooService
|
|
344
350
|
dputs(2) { "Erasing data of #{k}" }
|
345
351
|
v.delete_all(local_only)
|
346
352
|
}
|
347
|
-
ConfigBases.
|
353
|
+
ConfigBases.init_load
|
348
354
|
end
|
349
355
|
|
350
356
|
def self.save_all()
|
@@ -376,6 +382,8 @@ class Entities < RPCQooxdooService
|
|
376
382
|
def self.reload
|
377
383
|
Entities.save_all
|
378
384
|
Entities.delete_all_data(true)
|
385
|
+
SQLite.dbs_close_all
|
386
|
+
SQLite.dbs_open_load_migrate
|
379
387
|
Entities.load_all
|
380
388
|
end
|
381
389
|
|
@@ -445,7 +453,7 @@ class Entity
|
|
445
453
|
|
446
454
|
alias_method :old_respond_to?, :respond_to?
|
447
455
|
|
448
|
-
def respond_to?(cmd)
|
456
|
+
def respond_to?(cmd, all = false)
|
449
457
|
field = cmd.to_s
|
450
458
|
if field == 'to_ary'
|
451
459
|
dputs(4) { 'not responding to_ary' }
|
@@ -455,7 +463,7 @@ class Entity
|
|
455
463
|
when /=$/
|
456
464
|
return true
|
457
465
|
else
|
458
|
-
return (@proxy.get_value(cmd) or super)
|
466
|
+
return (@proxy.get_value(cmd) or super(cmd, all))
|
459
467
|
end
|
460
468
|
end
|
461
469
|
|
@@ -574,7 +582,7 @@ class Entity
|
|
574
582
|
if not raw and e
|
575
583
|
v = @proxy.get_value(f)
|
576
584
|
|
577
|
-
if e.class ==
|
585
|
+
if e.class == Integer and v and v.dtype == 'entity'
|
578
586
|
dputs(5) { "Getting instance for #{v.inspect}" }
|
579
587
|
dputs(5) { "Getting instance with #{e.class} - #{e.inspect}" }
|
580
588
|
dputs(5) { "Field = #{field}; id = #{@id}" }
|
@@ -602,19 +610,6 @@ class Entity
|
|
602
610
|
field = field_orig.to_s
|
603
611
|
(direct = field =~ /^_/) and field.sub!(/^_/, '')
|
604
612
|
dputs(4) { "Direct is #{direct.inspect} for field #{field_orig.inspect}" }
|
605
|
-
=begin
|
606
|
-
v = if value.is_a? Entity
|
607
|
-
dputs( 3 ){ "Converting #{value} to #{value.id}" }
|
608
|
-
value.id
|
609
|
-
elsif value.is_a? Array
|
610
|
-
dputs(3){"Storing an array #{value.inspect}"}
|
611
|
-
dp value.collect{|val|
|
612
|
-
val.is_a?( Entity ) ? val.id : val
|
613
|
-
}
|
614
|
-
else
|
615
|
-
value
|
616
|
-
end
|
617
|
-
=end
|
618
613
|
v = value
|
619
614
|
dputs(4) { "Self is #{self.public_methods.sort.inspect}" }
|
620
615
|
if (self.public_methods.index("#{field}=".to_sym)) && (not direct)
|