ginjo-rfm 3.0.9 → 3.0.10
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 +13 -5
- data/CHANGELOG.md +61 -40
- data/README.md +8 -8
- data/lib/rfm.rb +66 -67
- data/lib/rfm/VERSION +1 -1
- data/lib/rfm/base.rb +237 -241
- data/lib/rfm/database.rb +38 -24
- data/lib/rfm/error.rb +25 -25
- data/lib/rfm/layout.rb +217 -195
- data/lib/rfm/metadata/datum.rb +37 -37
- data/lib/rfm/metadata/field.rb +42 -39
- data/lib/rfm/metadata/field_control.rb +72 -72
- data/lib/rfm/metadata/layout_meta.rb +32 -32
- data/lib/rfm/metadata/resultset_meta.rb +74 -74
- data/lib/rfm/metadata/script.rb +3 -3
- data/lib/rfm/metadata/value_list_item.rb +30 -30
- data/lib/rfm/record.rb +80 -77
- data/lib/rfm/resultset.rb +63 -65
- data/lib/rfm/server.rb +31 -23
- data/lib/rfm/utilities/case_insensitive_hash.rb +4 -1
- data/lib/rfm/utilities/compound_query.rb +100 -101
- data/lib/rfm/utilities/config.rb +228 -218
- data/lib/rfm/utilities/connection.rb +65 -57
- data/lib/rfm/utilities/core_ext.rb +114 -119
- data/lib/rfm/utilities/factory.rb +122 -126
- data/lib/rfm/utilities/sax_parser.rb +1058 -1046
- data/lib/rfm/utilities/scope.rb +64 -0
- data/lib/rfm/version.rb +23 -7
- metadata +40 -39
data/lib/rfm/server.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'net/https'
|
2
2
|
require 'cgi'
|
3
|
+
|
3
4
|
module Rfm
|
4
5
|
# This class represents a single FileMaker server. It is initialized with basic
|
5
6
|
# connection information, including the hostname, port number, and default database
|
@@ -45,9 +46,9 @@ module Rfm
|
|
45
46
|
# * *host_name* is the host name this server points to
|
46
47
|
# * *port* is the port number this server communicates on
|
47
48
|
# * *state* is a hash of all server options used to initialize this server
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
|
50
|
+
|
51
|
+
|
51
52
|
# The Database object represents a single FileMaker Pro database. When you retrieve a Database
|
52
53
|
# object from a server, its account name and password are set to the account name and password you
|
53
54
|
# used when initializing the Server object. You can override this of course:
|
@@ -108,8 +109,8 @@ module Rfm
|
|
108
109
|
# * *state* is a hash of all server options used to initialize this server
|
109
110
|
class Server
|
110
111
|
include Config
|
111
|
-
|
112
|
-
|
112
|
+
|
113
|
+
|
113
114
|
# To create a Server object, you typically need at least a host name:
|
114
115
|
#
|
115
116
|
# myServer = Rfm::Server.new({:host => 'my.host.com'})
|
@@ -195,11 +196,11 @@ module Rfm
|
|
195
196
|
# :root_cert_path => '/usr/cert_file/'
|
196
197
|
# })
|
197
198
|
def initialize(*args)
|
198
|
-
|
199
|
-
|
199
|
+
config(*args)
|
200
|
+
raise Rfm::Error::RfmError.new(0, "New instance of Rfm::Server has no host name. Attempted name '#{state[:host]}'.") if state[:host].to_s == ''
|
200
201
|
@databases = Rfm::Factory::DbFactory.new(self)
|
201
202
|
end
|
202
|
-
|
203
|
+
|
203
204
|
# Access the database object representing a database on the server. For example:
|
204
205
|
#
|
205
206
|
# myServer['Customers']
|
@@ -212,25 +213,32 @@ module Rfm
|
|
212
213
|
# get no error at this point if the database you access doesn't exist. Instead, you'll
|
213
214
|
# receive an error when you actually try to perform some action on a layout from this
|
214
215
|
# database.
|
215
|
-
|
216
|
-
|
217
|
-
|
216
|
+
# def [](dbname, acnt=nil, pass=nil)
|
217
|
+
# self.db[dbname, acnt, pass]
|
218
|
+
# end
|
218
219
|
def_delegator :databases, :[]
|
219
|
-
|
220
|
+
|
220
221
|
attr_reader :databases #, :host_name, :port, :scheme, :state
|
221
222
|
# Legacy Rfm method to get/create databases from server object
|
222
223
|
alias_method :db, :databases
|
223
|
-
|
224
|
+
|
224
225
|
def config(*args)
|
225
|
-
|
226
|
-
|
226
|
+
super(:capture_strings_with=>[:host, :account_name, :password])
|
227
|
+
super(*args)
|
227
228
|
end
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
229
|
+
|
230
|
+
def host_name
|
231
|
+
state[:host]
|
232
|
+
end
|
233
|
+
|
234
|
+
def scheme
|
235
|
+
state[:ssl] ? "https" : "http"
|
236
|
+
end
|
237
|
+
|
238
|
+
def port
|
239
|
+
state[:ssl] && state[:port].nil? ? 443 : state[:port]
|
240
|
+
end
|
241
|
+
|
234
242
|
# Performs a raw FileMaker action. You will generally not call this method directly, but it
|
235
243
|
# is exposed in case you need to do something "under the hood."
|
236
244
|
#
|
@@ -258,6 +266,6 @@ module Rfm
|
|
258
266
|
# },
|
259
267
|
# { :max_records => 20 }
|
260
268
|
# )
|
261
|
-
|
269
|
+
|
262
270
|
end
|
263
|
-
end
|
271
|
+
end
|
@@ -1,114 +1,113 @@
|
|
1
1
|
# The classes in this module are used internally by RFM and are not intended for outside use.
|
2
2
|
module Rfm
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# Also allow find requests to be :omit.
|
4
|
+
# Class to build complex FMP queries.
|
5
|
+
# Perform Filemaker find using complex boolean logic (multiple value options for a single field),
|
6
|
+
# or create multiple find requests.
|
7
|
+
# Also allow find requests to be :omit.
|
9
8
|
class CompoundQuery < Array
|
10
|
-
|
11
|
-
attr_accessor :original_input, :query_type, :key_values, :key_arrays, :key_map, :key_map_string, :key_counter, :field_mapping
|
12
|
-
|
13
|
-
def self.build_test
|
14
|
-
new([{:field1=>['val1a','val1b','val1c'], :field2=>'val2'},{:omit=>true, :field3=>'val3', :field4=>'val4'}, {:omit=>true, :field5=>['val5a','val5b'], :field6=>['val6a','val6b']}], {})
|
15
|
-
end
|
16
|
-
|
17
|
-
# New CompoundQuery objects expect one of 3 data types:
|
18
|
-
# * string/integer representing FMP internal record id
|
19
|
-
# * hash of find-criteria
|
20
|
-
# * array of find-criteria hashes
|
21
|
-
#
|
22
|
-
# Returns self as ['-fmpaction', {:hash=>'of', :key=>'values'}, {:options=>'hash'}]
|
23
|
-
def initialize(query, options={})
|
24
|
-
@options = options
|
25
|
-
@field_mapping = options.delete(:field_mapping) || {}
|
26
|
-
@original_input = query
|
27
|
-
@key_values = {}
|
28
|
-
@key_arrays = []
|
29
|
-
@key_map = []
|
30
|
-
@key_map_string = ''
|
31
|
-
@key_counter = 0
|
32
9
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
10
|
+
attr_accessor :original_input, :query_type, :key_values, :key_arrays, :key_map, :key_map_string, :key_counter, :field_mapping
|
11
|
+
|
12
|
+
def self.build_test
|
13
|
+
new([{:field1=>['val1a','val1b','val1c'], :field2=>'val2'},{:omit=>true, :field3=>'val3', :field4=>'val4'}, {:omit=>true, :field5=>['val5a','val5b'], :field6=>['val6a','val6b']}], {})
|
14
|
+
end
|
15
|
+
|
16
|
+
# New CompoundQuery objects expect one of 3 data types:
|
17
|
+
# * string/integer representing FMP internal record id
|
18
|
+
# * hash of find-criteria
|
19
|
+
# * array of find-criteria hashes
|
20
|
+
#
|
21
|
+
# Returns self as ['-fmpaction', {:hash=>'of', :key=>'values'}, {:options=>'hash'}]
|
22
|
+
def initialize(query, options={})
|
23
|
+
@options = options
|
24
|
+
@field_mapping = options.delete(:field_mapping) || {}
|
25
|
+
@original_input = query
|
26
|
+
@key_values = {}
|
27
|
+
@key_arrays = []
|
28
|
+
@key_map = []
|
29
|
+
@key_map_string = ''
|
30
|
+
@key_counter = 0
|
31
|
+
|
32
|
+
case query
|
33
|
+
when Hash
|
34
|
+
if query.detect{|k,v| v.kind_of? Array or k == :omit}
|
35
|
+
@query_type = 'mixed'
|
36
|
+
else
|
37
|
+
@query_type = 'standard'
|
38
|
+
end
|
39
|
+
when Array
|
40
|
+
@query_type = 'compound'
|
41
|
+
else
|
42
|
+
@query_type = 'recid'
|
43
|
+
end
|
44
|
+
build_query
|
45
|
+
end
|
46
|
+
|
47
|
+
# Master control method to build output
|
48
|
+
def build_query(input=original_input)
|
49
|
+
case @query_type
|
50
|
+
when 'mixed', 'compound'
|
51
|
+
input.rfm_force_array.each do |hash|
|
52
|
+
build_key_map(build_key_values(hash))
|
53
|
+
end
|
54
|
+
translate_key_map
|
55
|
+
self.push '-findquery'
|
56
|
+
self.push @key_values.merge('-query'=>@key_map_string)
|
57
|
+
when 'standard'
|
58
|
+
self.push '-find'
|
59
|
+
self.push @original_input
|
60
|
+
when 'recid'
|
61
|
+
self.push '-find'
|
62
|
+
self.push '-recid' => @original_input.to_s
|
63
|
+
end
|
64
|
+
self.push @options
|
65
|
+
self
|
66
|
+
end
|
47
67
|
|
48
|
-
# Master control method to build output
|
49
|
-
def build_query(input=original_input)
|
50
|
-
case @query_type
|
51
|
-
when 'mixed', 'compound'
|
52
|
-
input.rfm_force_array.each do |hash|
|
53
|
-
build_key_map(build_key_values(hash))
|
54
|
-
end
|
55
|
-
translate_key_map
|
56
|
-
self.push '-findquery'
|
57
|
-
self.push @key_values.merge('-query'=>@key_map_string)
|
58
|
-
when 'standard'
|
59
|
-
self.push '-find'
|
60
|
-
self.push @original_input
|
61
|
-
when 'recid'
|
62
|
-
self.push '-find'
|
63
|
-
self.push '-recid' => @original_input.to_s
|
64
|
-
end
|
65
|
-
self.push @options
|
66
|
-
self
|
67
|
-
end
|
68
68
|
|
69
|
+
# Build key-value definitions and query map '-q1...'.
|
70
|
+
# Converts query_hash to fmresultset uri format for -findquery query type.
|
71
|
+
def build_key_values(input_hash)
|
72
|
+
input_hash = input_hash.clone
|
73
|
+
keyarray = []
|
74
|
+
omit = input_hash.delete(:omit)
|
75
|
+
input_hash.each do |key,val|
|
76
|
+
query_tag = []
|
77
|
+
val = val.rfm_force_array
|
78
|
+
val.each do |v|
|
79
|
+
@key_values["-q#{key_counter}"] = field_mapping[key] || key
|
80
|
+
@key_values["-q#{key_counter}.value"] = v
|
81
|
+
query_tag << "q#{key_counter}"
|
82
|
+
@key_counter += 1
|
83
|
+
end
|
84
|
+
keyarray << query_tag
|
85
|
+
end
|
86
|
+
(keyarray << :omit) if omit
|
87
|
+
@key_arrays << keyarray
|
88
|
+
keyarray
|
89
|
+
end
|
69
90
|
|
70
|
-
# Build key-value definitions and query map '-q1...'.
|
71
|
-
# Converts query_hash to fmresultset uri format for -findquery query type.
|
72
|
-
def build_key_values(input_hash)
|
73
|
-
input_hash = input_hash.clone
|
74
|
-
keyarray = []
|
75
|
-
omit = input_hash.delete(:omit)
|
76
|
-
input_hash.each do |key,val|
|
77
|
-
query_tag = []
|
78
|
-
val = val.rfm_force_array
|
79
|
-
val.each do |v|
|
80
|
-
@key_values["-q#{key_counter}"] = field_mapping[key] || key
|
81
|
-
@key_values["-q#{key_counter}.value"] = v
|
82
|
-
query_tag << "q#{key_counter}"
|
83
|
-
@key_counter += 1
|
84
|
-
end
|
85
|
-
keyarray << query_tag
|
86
|
-
end
|
87
|
-
(keyarray << :omit) if omit
|
88
|
-
@key_arrays << keyarray
|
89
|
-
keyarray
|
90
|
-
end
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
92
|
+
# Input array of arrays.
|
93
|
+
# Transform single key_array into key_map (array of requests).
|
94
|
+
# Creates all combinations of sub-arrays where each combination contains one element of each subarray.
|
95
|
+
def build_key_map(key_array)
|
96
|
+
key_array = key_array.clone
|
97
|
+
omit = key_array.delete(:omit)
|
98
|
+
len = key_array.length
|
99
|
+
flat = key_array.flatten
|
100
|
+
rslt = flat.combination(len).select{|c| key_array.all?{|a| (a & c).size > 0}}.each{|c| c.unshift(:omit) if omit}
|
101
|
+
@key_map.concat rslt
|
102
|
+
end
|
104
103
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
104
|
+
# Translate @key_map to FMP -query string
|
105
|
+
def translate_key_map(keymap=key_map)
|
106
|
+
keymap = keymap.clone
|
107
|
+
inner = keymap.collect {|a| "#{'!' if a.delete(:omit)}(#{a.join(',')})"}
|
108
|
+
outter = inner.join(';')
|
109
|
+
@key_map_string << outter
|
110
|
+
end
|
112
111
|
|
113
112
|
end # CompoundQuery
|
114
113
|
|
data/lib/rfm/utilities/config.rb
CHANGED
@@ -1,232 +1,242 @@
|
|
1
1
|
module Rfm
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
#
|
3
|
+
# Top level config hash accepts any defined config parameters,
|
4
|
+
# or group-name keys pointing to config subsets.
|
5
|
+
# The subsets can be any grouping of defined config parameters, as a hash.
|
6
|
+
# See CONFIG_KEYS for defined config parameters.
|
7
|
+
#
|
8
8
|
module Config
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
9
|
+
require 'yaml'
|
10
|
+
require 'erb'
|
11
|
+
|
12
|
+
CONFIG_KEYS = %w(
|
13
|
+
file_name
|
14
|
+
file_path
|
15
|
+
parser
|
16
|
+
host
|
17
|
+
port
|
18
|
+
proxy
|
19
|
+
account_name
|
20
|
+
password
|
21
|
+
database
|
22
|
+
layout
|
23
|
+
ignore_bad_data
|
24
|
+
ssl
|
25
|
+
root_cert
|
26
|
+
root_cert_name
|
27
|
+
root_cert_path
|
28
|
+
warn_on_redirect
|
29
|
+
raise_on_401
|
30
|
+
timeout
|
31
|
+
log_actions
|
32
|
+
log_responses
|
33
|
+
log_parser
|
34
|
+
use
|
35
|
+
parent
|
36
|
+
template
|
37
|
+
grammar
|
38
|
+
field_mapping
|
39
|
+
capture_strings_with
|
40
|
+
logger
|
41
|
+
)
|
42
|
+
|
43
|
+
CONFIG_DONT_STORE = %w(strings using parents symbols objects) #capture_strings_with)
|
44
|
+
|
45
45
|
extend self
|
46
46
|
@config = {}
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
47
|
+
|
48
|
+
# Set @config with args & options hash.
|
49
|
+
# Args should be symbols representing configuration groups,
|
50
|
+
# with optional config hash as last arg, to be merged on top.
|
51
|
+
# Returns @config.
|
52
|
+
#
|
53
|
+
# == Sets @config with :use => :group1, :layout => 'my_layout'
|
54
|
+
# config :group1, :layout => 'my_layout
|
55
|
+
#
|
56
|
+
# Factory.server, Factory.database, Factory.layout, and Base.config can take
|
57
|
+
# a string as the first argument, refering to the relevent server/database/layout name.
|
58
|
+
#
|
59
|
+
# == Pass a string as the first argument, to be used in the immediate context
|
60
|
+
# config 'my_layout' # in the model, to set model configuration
|
61
|
+
# Factory.layout 'my_layout', :my_group # to get a layout from settings in :my_group
|
62
|
+
#
|
63
|
+
def config(*args, &block)
|
64
|
+
@config ||= {}
|
65
|
+
return @config if args.empty?
|
66
|
+
config_write(*args, &block)
|
67
|
+
@config
|
68
|
+
end
|
69
|
+
|
70
|
+
# Sets @config just as above config method, but clears @config first.
|
71
|
+
def config_clear(*args)
|
72
|
+
@config = {}
|
73
|
+
return @config if args.empty?
|
74
|
+
config_write(*args)
|
75
|
+
@config
|
76
|
+
end
|
77
|
+
|
78
|
+
# Reads compiled config, including filters and ad-hoc configuration params passed in.
|
79
|
+
# If first n parameters are strings, they will be appended to config[:strings].
|
80
|
+
# If next n parameters are symbols, they will be used to filter the result. These
|
81
|
+
# filters will override all stored config[:use] settings.
|
82
|
+
# The final optional hash should be ad-hoc config settings.
|
83
|
+
#
|
84
|
+
# == Gets top level settings, merged with group settings, merged with local and ad-hoc settings.
|
85
|
+
# get_config :my_server_group, :layout => 'my_layout' # This gets top level settings,
|
86
|
+
#
|
87
|
+
# == Gets top level settings, merged with local and ad-hoc settings.
|
88
|
+
# get_config :layout => 'my_layout
|
89
|
+
#
|
90
|
+
def get_config(*arguments)
|
91
|
+
#puts caller_locations(1,1)[0]
|
92
|
+
args = arguments.clone
|
93
|
+
@config ||= {}
|
94
|
+
options = config_extract_options!(*args)
|
95
|
+
strings = options[:strings].rfm_force_array || []
|
96
|
+
symbols = options[:symbols].rfm_force_array.concat(options[:hash][:use].rfm_force_array) || []
|
97
|
+
objects = options[:objects].rfm_force_array || []
|
98
|
+
|
99
|
+
rslt = config_merge_with_parent(symbols).merge(options[:hash])
|
100
|
+
#using = rslt[:using].rfm_force_array
|
101
|
+
sanitize_config(rslt, CONFIG_DONT_STORE, false)
|
102
|
+
rslt[:using].delete ""
|
103
|
+
rslt[:parents].delete ""
|
104
|
+
rslt.merge(:strings=>strings, :objects=>objects)
|
105
|
+
end
|
106
|
+
|
107
|
+
def state(*args)
|
108
|
+
return @_state if args.empty? && !@state.nil? && (RUBY_VERSION[0,1].to_i > 1 ? (caller_locations(1,1) == @_last_state_caller) : false)
|
109
|
+
@_state = get_config(*args)
|
110
|
+
(@_last_state_caller = caller_locations(1,1)) if RUBY_VERSION[0,1].to_i > 1
|
111
|
+
@_state
|
112
|
+
end
|
113
|
+
|
114
|
+
def log
|
115
|
+
Rfm.log
|
116
|
+
end
|
117
|
+
|
118
|
+
protected
|
119
|
+
|
120
|
+
# Get or load a config file as the top-level config (above RFM_CONFIG constant).
|
121
|
+
# Default file name is rfm.yml.
|
122
|
+
# Default paths are '' and 'config/'.
|
123
|
+
# File name & paths can be set in RFM_CONFIG and Rfm.config.
|
124
|
+
# Change file name with :file_name => 'something.else'
|
125
|
+
# Change file paths with :file_path => ['array/of/', 'file/paths/']
|
126
|
+
def get_config_file
|
127
|
+
@@config_file_data ||= (
|
128
|
+
config_file_name = @config[:file_name] || (RFM_CONFIG[:file_name] rescue nil) || 'rfm.yml'
|
129
|
+
config_file_paths = [''] | [(@config[:file_path] || (RFM_CONFIG[:file_path] rescue nil) || %w( config/ ./ ))].flatten
|
130
|
+
config_file_paths.collect do |path|
|
131
|
+
(YAML.load(ERB.new(File.read(File.join(path, config_file_name))).result) rescue {})
|
132
|
+
end.inject({}){|h,a| h.merge(a)}
|
133
|
+
) || {}
|
134
|
+
end
|
135
|
+
|
136
|
+
# Get the top-level configuration from yml file and RFM_CONFIG
|
137
|
+
def get_config_base
|
138
|
+
get_config_file.merge((defined?(RFM_CONFIG) and RFM_CONFIG.is_a?(Hash)) ? RFM_CONFIG : {})
|
139
|
+
end
|
140
|
+
|
141
|
+
# Get the parent configuration object according to @config[:parent]
|
142
142
|
def get_config_parent
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
143
|
+
@config ||= {}
|
144
|
+
case
|
145
|
+
when @config[:parent].is_a?(String)
|
146
|
+
eval(@config[:parent])
|
147
|
+
when !@config[:parent].nil? && @config[:parent].is_a?(Rfm::Config)
|
148
|
+
@config[:parent]
|
149
|
+
else
|
150
|
+
eval('Rfm::Config')
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Merge args into @config, as :use=>[arg1, arg2, ...]
|
155
|
+
# Then merge optional config hash into @config.
|
156
|
+
# Pass in a block to use with parsed config in args.
|
157
|
+
def config_write(*args) #(opt, args)
|
158
|
+
options = config_extract_options!(*args)
|
159
|
+
options[:symbols].each{|a| @config.merge!(:use=>a.to_sym){|h,v1,v2| [v1].flatten << v2 }}
|
160
|
+
@config.merge!(options[:hash]).reject! {|k,v| CONFIG_DONT_STORE.include? k.to_s}
|
161
|
+
#options[:hash][:capture_strings_with].rfm_force_array.each do |label|
|
162
|
+
@config[:capture_strings_with].rfm_force_array.each do |label|
|
163
|
+
string = options[:strings].delete_at(0)
|
164
|
+
(@config[label] = string) if string && !string.empty?
|
165
|
+
end
|
166
|
+
parent = (options[:objects].delete_at(0) || options[:hash][:parent])
|
167
|
+
(@config[:parent] = parent) if parent
|
168
|
+
yield(options) if block_given?
|
169
|
+
end
|
170
|
+
|
171
|
+
# Get composite config from all levels, processing :use parameters at each level
|
172
|
+
def config_merge_with_parent(filters=nil)
|
173
|
+
@config ||= {}
|
174
|
+
|
175
|
+
# Get upstream compilation
|
173
176
|
upstream = if (self != Rfm::Config)
|
174
|
-
|
175
|
-
|
177
|
+
#puts [self, @config[:parent], get_config_parent].join(', ')
|
178
|
+
get_config_parent.config_merge_with_parent
|
176
179
|
else
|
177
|
-
|
180
|
+
get_config_base
|
178
181
|
end.clone
|
179
|
-
|
182
|
+
|
180
183
|
upstream[:using] ||= []
|
181
184
|
upstream[:parents] ||= ['file', 'RFM_CONFIG']
|
182
185
|
|
183
|
-
|
186
|
+
filters = (@config[:use].rfm_force_array | filters.rfm_force_array).compact
|
187
|
+
|
188
|
+
rslt = config_filter(upstream, filters).merge(config_filter(@config, filters))
|
184
189
|
|
185
|
-
|
190
|
+
rslt[:using].concat((@config[:use].rfm_force_array | filters).compact.flatten) #.join
|
191
|
+
rslt[:parents] << @config[:parent].to_s
|
186
192
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
#
|
193
|
+
rslt.delete :parent
|
194
|
+
|
195
|
+
rslt || {}
|
196
|
+
# rescue
|
197
|
+
# puts "Config#config_merge_with_parent for '#{self.class}' falied with #{$1}"
|
198
|
+
end
|
199
|
+
|
200
|
+
# Returns a configuration hash overwritten by :use filters in the hash
|
201
|
+
# that match passed-in filter names or any filter names contained within the hash's :use key.
|
202
|
+
def config_filter(conf, filters=nil)
|
203
|
+
conf = conf.clone
|
204
|
+
filters = (conf[:use].rfm_force_array | filters.rfm_force_array).compact
|
205
|
+
if (!filters.nil? && !filters.empty?)
|
206
|
+
filters.each do |f|
|
207
|
+
next unless conf[f]
|
208
|
+
conf.merge!(conf[f] || {})
|
209
|
+
end
|
210
|
+
end
|
211
|
+
conf.delete(:use)
|
212
|
+
conf
|
213
|
+
end
|
214
|
+
|
215
|
+
# Extract arguments into strings, symbols, objects, hash.
|
216
|
+
def config_extract_options!(*args)
|
217
|
+
strings, symbols, objects = [], [], []
|
218
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
219
|
+
args.each do |a|
|
220
|
+
case
|
221
|
+
when a.is_a?(String)
|
222
|
+
strings << a
|
223
|
+
when a.is_a?(Symbol)
|
224
|
+
symbols << a
|
225
|
+
else
|
226
|
+
objects << a
|
227
|
+
end
|
228
|
+
end
|
229
|
+
{:strings=>strings, :symbols=>symbols, :objects=>objects, :hash=>options}
|
195
230
|
end
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
def config_extract_options!(*args)
|
209
|
-
strings, symbols, objects = [], [], []
|
210
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
211
|
-
args.each do |a|
|
212
|
-
case
|
213
|
-
when a.is_a?(String); strings << a
|
214
|
-
when a.is_a?(Symbol); symbols << a
|
215
|
-
else objects << a
|
216
|
-
end
|
217
|
-
end
|
218
|
-
{:strings=>strings, :symbols=>symbols, :objects=>objects, :hash=>options}
|
219
|
-
end
|
220
|
-
|
221
|
-
# Remove un-registered keys from a configuration hash.
|
222
|
-
# Keep should be a list of strings representing keys to keep.
|
223
|
-
def sanitize_config(conf={}, keep=[], dupe=false)
|
224
|
-
(conf = conf.clone) if dupe
|
225
|
-
conf.reject!{|k,v| (!CONFIG_KEYS.include?(k.to_s) or [{},[],''].include?(v)) and !keep.include? k.to_s }
|
226
|
-
conf
|
227
|
-
end
|
228
|
-
|
229
|
-
|
230
|
-
end # module Config
|
231
|
-
|
232
|
-
end # module Rfm
|
231
|
+
|
232
|
+
# Remove un-registered keys from a configuration hash.
|
233
|
+
# Keep should be a list of strings representing keys to keep.
|
234
|
+
def sanitize_config(conf={}, keep=[], dupe=false)
|
235
|
+
(conf = conf.clone) if dupe
|
236
|
+
conf.reject!{|k,v| (!CONFIG_KEYS.include?(k.to_s) or [{},[],''].include?(v)) and !keep.include? k.to_s }
|
237
|
+
conf
|
238
|
+
end
|
239
|
+
|
240
|
+
end # module Config
|
241
|
+
|
242
|
+
end # module Rfm
|