ginjo-rfm 1.4.4 → 2.0.pre31

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.
@@ -0,0 +1,115 @@
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
+ #
8
+ # All filters are honored, unless filters are included in calls to get_config,
9
+ # in which case only the immediately specified filters will be used.
10
+ #
11
+ # Do not put a :use=>:group filter in a subset (maybe future feature?).
12
+ # Do not put a :use=>:group filter in the top-level global parameters.
13
+ # Do not put subsets in non-top-level configs. (maybe future feature?)
14
+ #
15
+ module Config
16
+ CONFIG_KEYS = %w(parser host port account_name password database layout ssl root_cert root_cert_name root_cert_path warn_on_redirect raise_on_401 timeout log_actions log_responses log_parser use parent)
17
+
18
+ extend self
19
+ @config = {}
20
+
21
+ # Set @config with args & options hash.
22
+ # Args should be symbols representing configuration groups,
23
+ # with optional config hash as last arg, to be merged on top.
24
+ # Returns @config.
25
+ #
26
+ # == Sets @config with :use => :group1, :layout => 'my_layout'
27
+ # config :group1, :layout => 'my_layout
28
+ #
29
+ # Factory.server, Factory.database, Factory.layout, and Base.config can take
30
+ # a string as the first argument, refering to the relevent server/database/layout name.
31
+ #
32
+ # == Pass a string as the first argument, to be used in the immediate context
33
+ # config 'my_layout' # in the model, to set model configuration
34
+ # Factory.layout 'my_layout', :my_group # to get a layout from settings in :my_group
35
+ #
36
+ def config(*args, &block)
37
+ opt = args.rfm_extract_options!
38
+ @config ||= {}
39
+ config_write(opt, args, &block)
40
+ @config
41
+ end
42
+
43
+ # Sets @config just as above config method, but clears @config first.
44
+ def config_clear(*args)
45
+ opt = args.rfm_extract_options!
46
+ @config = {}
47
+ config_write(opt, args)
48
+ @config
49
+ end
50
+
51
+ # Reads compiled config, including filters and ad-hoc configuration params passed in.
52
+ # If first n parameters are strings, they will be appended to config[:strings].
53
+ # If next n parameters are symbols, they will be used to filter the result. These
54
+ # filters will override all stored config[:use] settings.
55
+ # The final optional hash should be ad-hoc config settings.
56
+ #
57
+ # == Gets top level settings, merged with group settings, merged with local and ad-hoc settings.
58
+ # get_config :my_server_group, :layout => 'my_layout' # This gets top level settings,
59
+ #
60
+ # == Gets top level settings, merged with local and ad-hoc settings.
61
+ # get_config :layout => 'my_layout
62
+ #
63
+ def get_config(*args)
64
+ @config ||= {}
65
+ opt = args.rfm_extract_options!
66
+ strings = []
67
+ while args[0].is_a?(String) do; strings << args.shift; end
68
+ if args.size == 0
69
+ config_filter(config_merge_with_parent)
70
+ else
71
+ config_filter(config_merge_with_parent, args)
72
+ end.merge(opt).merge(:strings=>strings)
73
+ end
74
+
75
+ protected
76
+
77
+
78
+ # Merge args into @config, as :use=>[arg1, arg2, ...]
79
+ # Then merge optional config hash into @config.
80
+ # Pass in a block to use with strings in args. See base.rb.
81
+ def config_write(opt, args)
82
+ strings = []; while args[0].is_a?(String) do; strings << args.shift; end
83
+ args.each{|a| @config.merge!(:use=>a.to_sym)}
84
+ @config.merge!(opt)
85
+ yield(strings) if block_given?
86
+ end
87
+
88
+ # Get composite config from all levels, adding :use parameters to a
89
+ # temporary top-level value.
90
+ def config_merge_with_parent
91
+ remote = if (self != Rfm::Config)
92
+ eval(@config[:parent] || 'Rfm::Config').config_merge_with_parent rescue {}
93
+ else
94
+ (defined?(RFM_CONFIG) and RFM_CONFIG.is_a?(Hash)) ? RFM_CONFIG : {}
95
+ end
96
+
97
+ use = (remote[:use].rfm_force_array | @config[:use].rfm_force_array).compact
98
+ remote.merge(@config).merge(:use=>use)
99
+ end
100
+
101
+ # Given config hash, return filtered. Filters should be symbols.
102
+ def config_filter(conf, filters=nil)
103
+ filters ||= conf[:use].rfm_force_array if !conf[:use].blank?
104
+ filters.each{|f| next unless conf[f]; conf.merge!(conf[f] || {})} if !filters.blank?
105
+ conf.reject!{|k,v| !CONFIG_KEYS.include?(k.to_s) or v.to_s == '' }
106
+ conf
107
+ end
108
+
109
+ # This loads RFM_CONFIG into @config. It is not necessary,
110
+ # as get_config will merge all configuration into RFM_CONFIG at runtime.
111
+ #config RFM_CONFIG if defined? RFM_CONFIG
112
+
113
+ end # module Config
114
+
115
+ end # module Rfm
@@ -0,0 +1,90 @@
1
+ require 'forwardable'
2
+
3
+ Module.module_eval do
4
+ # Adds ability to forward methods to other objects using 'def_delegator'
5
+ include Forwardable
6
+ end
7
+
8
+ class Object # @private :nodoc: all
9
+
10
+ #extend Forwardable
11
+
12
+ # Adds methods to put instance variables in rfm_metaclass, plus getter/setters
13
+ # This is useful to hide instance variables in objects that would otherwise show "too much" information.
14
+ def self.meta_attr_accessor(*names)
15
+ meta_attr_reader(*names)
16
+ meta_attr_writer(*names)
17
+ end
18
+
19
+ def self.meta_attr_reader(*names)
20
+ names.each do |n|
21
+ define_method(n.to_s) {rfm_metaclass.instance_variable_get("@#{n}")}
22
+ end
23
+ end
24
+
25
+ def self.meta_attr_writer(*names)
26
+ names.each do |n|
27
+ define_method(n.to_s + "=") {|val| rfm_metaclass.instance_variable_set("@#{n}", val)}
28
+ end
29
+ end
30
+
31
+ # Wrap an object in Array, if not already an Array,
32
+ # since XmlMini doesn't know which will be returnd for any particular element.
33
+ # See Rfm Layout & Record where this is used.
34
+ def rfm_force_array
35
+ self.is_a?(Array) ? self : [self]
36
+ end
37
+
38
+ # Just testing this functionality
39
+ def local_methods
40
+ self.methods - self.class.superclass.methods
41
+ end
42
+
43
+ private
44
+
45
+ # Like singleton_method or 'metaclass' from ActiveSupport.
46
+ def rfm_metaclass
47
+ class << self
48
+ self
49
+ end
50
+ end
51
+
52
+ # Get the superclass object of self.
53
+ def rfm_super
54
+ SuperProxy.new(self)
55
+ end
56
+
57
+ end # Object
58
+
59
+
60
+ class Array
61
+ # Taken from ActiveSupport extract_options!.
62
+ def rfm_extract_options!
63
+ last.is_a?(::Hash) ? pop : {}
64
+ end
65
+ end # Array
66
+
67
+ # Allows access to superclass object
68
+ class SuperProxy
69
+ def initialize(obj)
70
+ @obj = obj
71
+ end
72
+
73
+ def method_missing(meth, *args, &blk)
74
+ @obj.class.superclass.instance_method(meth).bind(@obj).call(*args, &blk)
75
+ end
76
+ end # SuperProxy
77
+
78
+
79
+ class Time
80
+ # Returns array of [date,time] in format suitable for FMP.
81
+ def to_fm_components(reset_time_if_before_today=false)
82
+ d = self.strftime('%m/%d/%Y')
83
+ t = if (Date.parse(self.to_s) < Date.today) and reset_time_if_before_today==true
84
+ "00:00:00"
85
+ else
86
+ self.strftime('%T')
87
+ end
88
+ [d,t]
89
+ end
90
+ end # Time
@@ -7,32 +7,64 @@
7
7
 
8
8
 
9
9
  module Rfm
10
- module Factory # :nodoc: all
11
- class DbFactory < Rfm::CaseInsensitiveHash
10
+
11
+ module Factory
12
+ extend Config
13
+ config :parent=>'Rfm::Config'
14
+
15
+ class ServerFactory < Rfm::CaseInsensitiveHash # @private :nodoc: all
16
+
17
+ def [](host, conf = Factory.get_config) #(Factory.instance_variable_get(:@config) || {}))
18
+ conf[:host] = host
19
+ super(host) or (self[host] = Rfm::Server.new(conf.reject{|k,v| [:account_name, :password].include? k}))
20
+ end
21
+
22
+ # Potential refactor
23
+ # def [](*conf)
24
+ # options = Factory.get_config(*conf)
25
+ # server_name = options[:strings][0] || options[:host]
26
+ # options[:host] = server_name
27
+ # #server = servers[server_name, options]
28
+ # super(server_name) or (self[server_name] = Rfm::Server.new(options.reject{|k,v| [:account_name, :password].include? k}))
29
+ # end
30
+
31
+ end # ServerFactory
32
+
33
+
34
+ class DbFactory < Rfm::CaseInsensitiveHash # :nodoc: all
12
35
 
13
36
  def initialize(server)
14
37
  @server = server
15
38
  @loaded = false
16
39
  end
17
40
 
18
- def [](dbname)
19
- super or (self[dbname] = Rfm::Database.new(dbname, @server))
41
+ def [](dbname, acnt=nil, pass=nil) #
42
+ db = (super(dbname) or (self[dbname] = Rfm::Database.new(dbname, @server)))
43
+ account_name = acnt || db.account_name || @server.state[:account_name]
44
+ password = pass || db.password || @server.state[:password]
45
+ db.account_name = account_name if account_name
46
+ db.password = password if password
47
+ db
20
48
  end
21
49
 
22
50
  def all
23
51
  if !@loaded
24
52
  Rfm::Resultset.new(@server, @server.connect(@server.state[:account_name], @server.state[:password], '-dbnames', {}).body, nil).each {|record|
25
53
  name = record['DATABASE_NAME']
26
- self[name] = Rfm::Database.new(name, @server) if self[name] == nil
54
+ self[name] = Rfm::Database.new(name, @server) if self.keys.find{|k| k.to_s.downcase == name.to_s.downcase} == nil
27
55
  }
28
56
  @loaded = true
29
57
  end
30
- self.keys
58
+ self
59
+ end
60
+
61
+ def names
62
+ keys
31
63
  end
32
64
 
33
- end
65
+ end # DbFactory
34
66
 
35
- class LayoutFactory < Rfm::CaseInsensitiveHash
67
+ class LayoutFactory < Rfm::CaseInsensitiveHash # :nodoc: all
36
68
 
37
69
  def initialize(server, database)
38
70
  @server = server
@@ -46,18 +78,24 @@ module Rfm
46
78
 
47
79
  def all
48
80
  if !@loaded
49
- Rfm::Resultset.new(@server, @server.connect(@server.state[:account_name], @server.state[:password], '-layoutnames', {"-db" => @database.name}).body, nil).each {|record|
81
+ Rfm::Resultset.new(@server, @server.connect(@database.account_name, @database.password, '-layoutnames', {"-db" => @database.name}).body, nil).each {|record|
50
82
  name = record['LAYOUT_NAME']
51
83
  self[name] = Rfm::Layout.new(name, @database) if self[name] == nil
52
84
  }
53
85
  @loaded = true
54
86
  end
55
- self.keys
87
+ self
56
88
  end
57
89
 
58
- end
90
+ def names
91
+ keys
92
+ end
93
+
94
+
95
+
96
+ end # LayoutFactory
59
97
 
60
- class ScriptFactory < Rfm::CaseInsensitiveHash
98
+ class ScriptFactory < Rfm::CaseInsensitiveHash # :nodoc: all
61
99
 
62
100
  def initialize(server, database)
63
101
  @server = server
@@ -71,15 +109,60 @@ module Rfm
71
109
 
72
110
  def all
73
111
  if !@loaded
74
- Rfm::Resultset.new(@server, @server.connect(@server.state[:account_name], @server.state[:password], '-scriptnames', {"-db" => @database.name}).body, nil).each {|record|
112
+ Rfm::Resultset.new(@server, @server.connect(@database.account_name, @database.password, '-scriptnames', {"-db" => @database.name}).body, nil).each {|record|
75
113
  name = record['SCRIPT_NAME']
76
114
  self[name] = Rfm::Metadata::Script.new(name, @database) if self[name] == nil
77
115
  }
78
116
  @loaded = true
79
117
  end
80
- self.keys
118
+ self
81
119
  end
120
+
121
+ def names
122
+ keys
123
+ end
124
+
125
+ end # ScriptFactory
126
+
127
+
128
+
129
+ class << self
130
+
131
+ def servers
132
+ @servers ||= ServerFactory.new
133
+ end
134
+
135
+ # Returns Rfm::Server instance, given config hash or array
136
+ def server(*conf)
137
+ options = get_config(*conf)
138
+ server_name = options[:strings][0] || options[:host]
139
+ raise Rfm::Error::RfmError.new(0, 'A host name is needed to create a server object.') if server_name.blank?
140
+ server = servers[server_name, options]
141
+ end
142
+ # Potential refactor
143
+ #def_delegator 'Rfm::Factory::ServerFactory', :[], :server #, :[]
144
+
145
+ # Returns Rfm::Db instance, given config hash or array
146
+ def db(*conf)
147
+ options = get_config(*conf)
148
+ db_name = options[:strings][0] || options[:database]
149
+ raise Rfm::Error::RfmError.new(0, 'A database name is needed to create a database object.') if db_name.blank?
150
+ account_name = options[:strings][1] || options[:account_name]
151
+ password = options[:strings][2] || options[:password]
152
+ db = server(options)[db_name, account_name, password]
153
+ end
154
+
155
+ alias_method :database, :db
156
+
157
+ # Returns Rfm::Layout instance, given config hash or array
158
+ def layout(*conf)
159
+ options = get_config(*conf)
160
+ layout_name = options[:strings][0] || options[:layout]
161
+ raise Rfm::Error::RfmError.new(0, 'A layout name is needed to create a layout object.') if layout_name.blank?
162
+ layout = db(options)[layout_name]
163
+ end
164
+
165
+ end # class << self
82
166
 
83
- end
84
- end
85
- end
167
+ end # Factory
168
+ end # Rfm
@@ -0,0 +1,94 @@
1
+ module Rfm
2
+ module XmlParser # @private :nodoc: all
3
+
4
+ extend Config
5
+ config :parent=>'Rfm::Config'
6
+
7
+ extend self
8
+
9
+ # Backend configurations
10
+ BACKENDS = ActiveSupport::OrderedHash.new
11
+
12
+ BACKENDS[:jdom] = {:require=>'jdom', :class => 'JDOM'}
13
+ BACKENDS[:libxml] = {:require=>'libxml', :class => 'LibXML'}
14
+ BACKENDS[:libxmlsax] = {:require=>'libxml', :class => 'LibXMLSAX'}
15
+ BACKENDS[:nokogirisax] = {:require=>'nokogiri', :class => proc{ActiveSupport::VERSION; 'NokogiriSAX'}}
16
+ BACKENDS[:nokogiri] = {:require=>'nokogiri', :class => 'Nokogiri'}
17
+ BACKENDS[:hpricot] = {:require=>'hpricot', :class => proc{
18
+ # Hpricot module is part of Rfm, not XmlMini,
19
+ # and needs to be handed manually to XmlMini.
20
+ require File.join(File.dirname(__FILE__), '../xml_mini/hpricot.rb')
21
+ ActiveSupport::XmlMini_Hpricot}}
22
+ BACKENDS[:rexml] = {:require=>'rexml/document', :class=>'REXML'}
23
+
24
+
25
+ # Main parsing method.
26
+ # Options
27
+ # :namespace => false # strip out namespace (default)
28
+ # :parser => :libxml, :libxmlsax, :nokogirisax, :nokogiri, :hpricot, :rexml
29
+ # :parser => CustomParsingModule # see ActiveSupport::XmlMini
30
+ def new(string_or_file, opts={})
31
+ string_or_file.gsub!(/xmlns=\"[^\"]*\"/,'') if (string_or_file.class == String and opts[:namespace] == false)
32
+ unless opts[:parser] and get_backend_from_hash(opts[:parser]).to_s != self.backend.to_s
33
+ warn "XmlParser default: #{ActiveSupport::XmlMini.backend.to_s}" if get_config[:log_parser] == true
34
+ ActiveSupport::XmlMini.parse(string_or_file)
35
+ else
36
+ warn "XmlParser backend: #{get_backend_from_hash(opts[:parser]).to_s}" if get_config[:log_parser] == true
37
+ ActiveSupport::XmlMini.with_backend(get_backend_from_hash(opts[:parser])) {ActiveSupport::XmlMini.parse(string_or_file)}
38
+ end
39
+ end
40
+
41
+ # Shortcut to XmlMini config getter.
42
+ # If a parameter is passed, it will be used to get the local backend description
43
+ # from the BACKENDS hash, instead of the XmlMini backend.
44
+ def backend(name=nil)
45
+ return ActiveSupport::XmlMini.backend unless name
46
+ get_backend_from_hash(name)
47
+ end
48
+
49
+ # Shortcut to XmlMini config setter.
50
+ def backend=(name)
51
+ if name.is_a? Symbol
52
+ set_backend_via_hash(name)
53
+ else
54
+ ActiveSupport::XmlMini.backend = name
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ # Given name, return backend config from BACKENDS, including any preloading.
61
+ # Will raise LoadError if can't load backend.
62
+ def get_backend_from_hash(name)
63
+ backend_hash = BACKENDS[name.to_sym]
64
+ require backend_hash[:require]
65
+ backend_hash[:class].is_a?(Proc) ? backend_hash[:class].call : backend_hash[:class]
66
+ end
67
+
68
+ # Set XmlMini backend, given symbol matching one of the BACKENDS.
69
+ def set_backend_via_hash(name)
70
+ ActiveSupport::XmlMini.backend = get_backend_from_hash(name)
71
+ end
72
+
73
+ # Select the best backend from BACKENDS, returns backend config.
74
+ def decide_backend
75
+ string_or_class = catch(:done) do
76
+ BACKENDS.keys.each do |name|
77
+ begin
78
+ result = get_backend_from_hash name
79
+ throw(:done, result)
80
+ rescue LoadError, StandardError
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ # Set XmlMini backend when this file loads.
87
+ begin
88
+ self.backend = get_backend_from_hash(get_config[:parser])
89
+ rescue
90
+ self.backend = decide_backend
91
+ end
92
+
93
+ end # XmlParser
94
+ end # Rfm