ginjo-rfm 3.0.9 → 3.0.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|