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.
@@ -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
- config(*args)
199
- raise Rfm::Error::RfmError.new(0, "New instance of Rfm::Server has no host name. Attempted name '#{state[:host]}'.") if state[:host].to_s == ''
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
- # def [](dbname, acnt=nil, pass=nil)
216
- # self.db[dbname, acnt, pass]
217
- # end
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
- super(:capture_strings_with=>[:host, :account_name, :password])
226
- super(*args)
226
+ super(:capture_strings_with=>[:host, :account_name, :password])
227
+ super(*args)
227
228
  end
228
-
229
-
230
- def host_name; state[:host]; end
231
- def scheme; state[:ssl] ? "https" : "http"; end
232
- def port; state[:ssl] && state[:port].nil? ? 443 : state[:port]; end
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,10 +1,13 @@
1
1
  module Rfm
2
2
  class CaseInsensitiveHash < Hash
3
+
3
4
  def []=(key, value)
4
5
  super(key.to_s.downcase, value)
5
6
  end
7
+
6
8
  def [](key)
7
9
  super(key.to_s.downcase)
8
10
  end
11
+
9
12
  end
10
- end
13
+ 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
- # Class to build complex FMP queries.
6
- # Perform Filemaker find using complex boolean logic (multiple value options for a single field),
7
- # or create multiple find requests.
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
- case query
34
- when Hash
35
- if query.detect{|k,v| v.kind_of? Array or k == :omit}
36
- @query_type = 'mixed'
37
- else
38
- @query_type = 'standard'
39
- end
40
- when Array
41
- @query_type = 'compound'
42
- else
43
- @query_type = 'recid'
44
- end
45
- build_query
46
- end
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
- # Input array of arrays.
94
- # Transform single key_array into key_map (array of requests).
95
- # Creates all combinations of sub-arrays where each combination contains one element of each subarray.
96
- def build_key_map(key_array)
97
- key_array = key_array.clone
98
- omit = key_array.delete(:omit)
99
- len = key_array.length
100
- flat = key_array.flatten
101
- rslt = flat.combination(len).select{|c| key_array.all?{|a| (a & c).size > 0}}.each{|c| c.unshift(:omit) if omit}
102
- @key_map.concat rslt
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
- # Translate @key_map to FMP -query string
106
- def translate_key_map(keymap=key_map)
107
- keymap = keymap.clone
108
- inner = keymap.collect {|a| "#{'!' if a.delete(:omit)}(#{a.join(',')})"}
109
- outter = inner.join(';')
110
- @key_map_string << outter
111
- end
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
 
@@ -1,232 +1,242 @@
1
1
  module Rfm
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
- #
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
- 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
-
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
- # 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]
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
- @config ||= {}
144
- parent = case
145
- when @config[:parent].is_a?(String); eval(@config[:parent])
146
- when !@config[:parent].nil? && @config[:parent].is_a?(Rfm::Config); @config[:parent]
147
- else eval('Rfm::Config')
148
- end
149
- end
150
-
151
- # Merge args into @config, as :use=>[arg1, arg2, ...]
152
- # Then merge optional config hash into @config.
153
- # Pass in a block to use with parsed config in args.
154
- def config_write(*args) #(opt, args)
155
- options = config_extract_options!(*args)
156
- options[:symbols].each{|a| @config.merge!(:use=>a.to_sym){|h,v1,v2| [v1].flatten << v2 }}
157
- @config.merge!(options[:hash]).reject! {|k,v| CONFIG_DONT_STORE.include? k.to_s}
158
- #options[:hash][:capture_strings_with].rfm_force_array.each do |label|
159
- @config[:capture_strings_with].rfm_force_array.each do |label|
160
- string = options[:strings].delete_at(0)
161
- (@config[label] = string) if string && !string.empty?
162
- end
163
- parent = (options[:objects].delete_at(0) || options[:hash][:parent])
164
- (@config[:parent] = parent) if parent
165
- yield(options) if block_given?
166
- end
167
-
168
- # Get composite config from all levels, processing :use parameters at each level
169
- def config_merge_with_parent(filters=nil)
170
- @config ||= {}
171
-
172
- # Get upstream compilation
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
- #puts [self, @config[:parent], get_config_parent].join(', ')
175
- get_config_parent.config_merge_with_parent
177
+ #puts [self, @config[:parent], get_config_parent].join(', ')
178
+ get_config_parent.config_merge_with_parent
176
179
  else
177
- get_config_base
180
+ get_config_base
178
181
  end.clone
179
-
182
+
180
183
  upstream[:using] ||= []
181
184
  upstream[:parents] ||= ['file', 'RFM_CONFIG']
182
185
 
183
- filters = (@config[:use].rfm_force_array | filters.rfm_force_array).compact
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
- rslt = config_filter(upstream, filters).merge(config_filter(@config, filters))
190
+ rslt[:using].concat((@config[:use].rfm_force_array | filters).compact.flatten) #.join
191
+ rslt[:parents] << @config[:parent].to_s
186
192
 
187
- rslt[:using].concat((@config[:use].rfm_force_array | filters).compact.flatten) #.join
188
- rslt[:parents] << @config[:parent].to_s
189
-
190
- rslt.delete :parent
191
-
192
- rslt || {}
193
- # rescue
194
- # puts "Config#config_merge_with_parent for '#{self.class}' falied with #{$1}"
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
- # Returns a configuration hash overwritten by :use filters in the hash
198
- # that match passed-in filter names or any filter names contained within the hash's :use key.
199
- def config_filter(conf, filters=nil)
200
- conf = conf.clone
201
- filters = (conf[:use].rfm_force_array | filters.rfm_force_array).compact
202
- filters.each{|f| next unless conf[f]; conf.merge!(conf[f] || {})} if (!filters.nil? && !filters.empty?)
203
- conf.delete(:use)
204
- conf
205
- end
206
-
207
- # Extract arguments into strings, symbols, objects, hash.
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