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.
@@ -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