ginjo-rfm 1.4.4 → 2.0.pre31

Sign up to get free protection for your applications and to get access to all the features.
@@ -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