ginjo-rfm 2.0.pre31 → 2.0.0
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.
- data/CHANGELOG.md +4 -4
- data/README.md +392 -146
- data/lib/rfm.rb +4 -5
- data/lib/rfm/VERSION +1 -1
- data/lib/rfm/base.rb +5 -11
- data/lib/rfm/database.rb +1 -1
- data/lib/rfm/layout.rb +64 -14
- data/lib/rfm/record.rb +3 -1
- data/lib/rfm/server.rb +5 -3
- data/lib/rfm/utilities/compound_query.rb +113 -0
- data/lib/rfm/utilities/config.rb +59 -16
- data/lib/rfm/utilities/factory.rb +18 -5
- data/lib/rfm/utilities/xml_parser.rb +18 -0
- data/lib/rfm/xml_mini/ox_sax.rb +91 -0
- data/lib/rfm/xml_mini/rexml_sax.rb +81 -0
- metadata +43 -14
- data/lib/rfm/utilities/complex_query.rb +0 -64
@@ -64,6 +64,8 @@ module Rfm
|
|
64
64
|
|
65
65
|
end # DbFactory
|
66
66
|
|
67
|
+
|
68
|
+
|
67
69
|
class LayoutFactory < Rfm::CaseInsensitiveHash # :nodoc: all
|
68
70
|
|
69
71
|
def initialize(server, database)
|
@@ -78,23 +80,34 @@ module Rfm
|
|
78
80
|
|
79
81
|
def all
|
80
82
|
if !@loaded
|
81
|
-
|
83
|
+
get_layout_names.each {|record|
|
82
84
|
name = record['LAYOUT_NAME']
|
83
|
-
|
85
|
+
begin
|
86
|
+
(self[name] = Rfm::Layout.new(name, @database)) unless !self[name].nil? or name.to_s.strip == ''
|
87
|
+
rescue
|
88
|
+
$stderr.puts $!
|
89
|
+
end
|
84
90
|
}
|
85
91
|
@loaded = true
|
86
92
|
end
|
87
93
|
self
|
88
94
|
end
|
95
|
+
|
96
|
+
def get_layout_names_xml
|
97
|
+
@server.connect(@database.account_name, @database.password, '-layoutnames', {"-db" => @database.name})
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_layout_names
|
101
|
+
Rfm::Resultset.new(@server, get_layout_names_xml.body, nil)
|
102
|
+
end
|
89
103
|
|
90
104
|
def names
|
91
105
|
keys
|
92
106
|
end
|
93
|
-
|
94
|
-
|
95
|
-
|
96
107
|
end # LayoutFactory
|
97
108
|
|
109
|
+
|
110
|
+
|
98
111
|
class ScriptFactory < Rfm::CaseInsensitiveHash # :nodoc: all
|
99
112
|
|
100
113
|
def initialize(server, database)
|
@@ -10,16 +10,34 @@ module Rfm
|
|
10
10
|
BACKENDS = ActiveSupport::OrderedHash.new
|
11
11
|
|
12
12
|
BACKENDS[:jdom] = {:require=>'jdom', :class => 'JDOM'}
|
13
|
+
|
14
|
+
BACKENDS[:oxsax] = {:require=>'ox', :class => proc{
|
15
|
+
# rexmlsax module is part of Rfm, not XmlMini,
|
16
|
+
# and needs to be handed manually to XmlMini.
|
17
|
+
require File.join(File.dirname(__FILE__), '../xml_mini/ox_sax.rb')
|
18
|
+
ActiveSupport::XmlMini_OxSAX}}
|
19
|
+
|
13
20
|
BACKENDS[:libxml] = {:require=>'libxml', :class => 'LibXML'}
|
21
|
+
|
14
22
|
BACKENDS[:libxmlsax] = {:require=>'libxml', :class => 'LibXMLSAX'}
|
23
|
+
|
15
24
|
BACKENDS[:nokogirisax] = {:require=>'nokogiri', :class => proc{ActiveSupport::VERSION; 'NokogiriSAX'}}
|
25
|
+
|
16
26
|
BACKENDS[:nokogiri] = {:require=>'nokogiri', :class => 'Nokogiri'}
|
27
|
+
|
17
28
|
BACKENDS[:hpricot] = {:require=>'hpricot', :class => proc{
|
18
29
|
# Hpricot module is part of Rfm, not XmlMini,
|
19
30
|
# and needs to be handed manually to XmlMini.
|
20
31
|
require File.join(File.dirname(__FILE__), '../xml_mini/hpricot.rb')
|
21
32
|
ActiveSupport::XmlMini_Hpricot}}
|
33
|
+
|
22
34
|
BACKENDS[:rexml] = {:require=>'rexml/document', :class=>'REXML'}
|
35
|
+
|
36
|
+
BACKENDS[:rexmlsax] = {:require=>'rexml/parsers/sax2parser', :class => proc{
|
37
|
+
# rexmlsax module is part of Rfm, not XmlMini,
|
38
|
+
# and needs to be handed manually to XmlMini.
|
39
|
+
require File.join(File.dirname(__FILE__), '../xml_mini/rexml_sax.rb')
|
40
|
+
ActiveSupport::XmlMini_REXMLSAX}}
|
23
41
|
|
24
42
|
|
25
43
|
# Main parsing method.
|
@@ -0,0 +1,91 @@
|
|
1
|
+
begin
|
2
|
+
require 'ox'
|
3
|
+
rescue LoadError => e
|
4
|
+
$stderr.puts "You don't have Ox installed in your application. Please add it to your Gemfile and run bundle install"
|
5
|
+
raise e
|
6
|
+
end
|
7
|
+
require 'active_support/core_ext/object/blank'
|
8
|
+
require 'stringio'
|
9
|
+
|
10
|
+
# = XmlMini Ox implementation using a SAX-based parser
|
11
|
+
# This Ox Sax parser was lifted directly from multi_xml gem.
|
12
|
+
module ActiveSupport
|
13
|
+
module XmlMini_OxSAX # @private :nodoc: all
|
14
|
+
|
15
|
+
extend self
|
16
|
+
|
17
|
+
def parse_error
|
18
|
+
Exception
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse(io)
|
22
|
+
if !io.respond_to?(:read)
|
23
|
+
io = StringIO.new(io || '')
|
24
|
+
end
|
25
|
+
handler = Handler.new
|
26
|
+
::Ox.sax_parse(handler, io, :convert_special => true)
|
27
|
+
handler.doc
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
class Handler
|
33
|
+
attr_accessor :stack
|
34
|
+
|
35
|
+
def initialize()
|
36
|
+
@stack = []
|
37
|
+
end
|
38
|
+
|
39
|
+
def doc
|
40
|
+
@stack[0]
|
41
|
+
end
|
42
|
+
|
43
|
+
def attr(name, value)
|
44
|
+
unless @stack.empty?
|
45
|
+
append(name, value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def text(value)
|
50
|
+
append('__content__', value)
|
51
|
+
end
|
52
|
+
|
53
|
+
def cdata(value)
|
54
|
+
append('__content__', value)
|
55
|
+
end
|
56
|
+
|
57
|
+
def start_element(name)
|
58
|
+
if @stack.empty?
|
59
|
+
@stack.push(Hash.new)
|
60
|
+
end
|
61
|
+
h = Hash.new
|
62
|
+
append(name, h)
|
63
|
+
@stack.push(h)
|
64
|
+
end
|
65
|
+
|
66
|
+
def end_element(name)
|
67
|
+
@stack.pop()
|
68
|
+
end
|
69
|
+
|
70
|
+
def error(message, line, column)
|
71
|
+
raise Exception.new("#{message} at #{line}:#{column}")
|
72
|
+
end
|
73
|
+
|
74
|
+
def append(key, value)
|
75
|
+
key = key.to_s
|
76
|
+
h = @stack.last
|
77
|
+
if h.has_key?(key)
|
78
|
+
v = h[key]
|
79
|
+
if v.is_a?(Array)
|
80
|
+
v << value
|
81
|
+
else
|
82
|
+
h[key] = [v, value]
|
83
|
+
end
|
84
|
+
else
|
85
|
+
h[key] = value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end # Handler
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'rexml/parsers/sax2parser'
|
2
|
+
require 'rexml/sax2listener'
|
3
|
+
require 'rexml/document'
|
4
|
+
require 'active_support/core_ext/object/blank'
|
5
|
+
require 'stringio'
|
6
|
+
|
7
|
+
# = XmlMini REXML implementation using the SAX2 parser
|
8
|
+
module ActiveSupport
|
9
|
+
module XmlMini_REXMLSAX
|
10
|
+
extend self
|
11
|
+
|
12
|
+
# Class that will build the hash while the XML document
|
13
|
+
# is being parsed using streaming events.
|
14
|
+
class HashBuilder
|
15
|
+
include REXML::SAX2Listener
|
16
|
+
|
17
|
+
CONTENT_KEY = '__content__'.freeze
|
18
|
+
HASH_SIZE_KEY = '__hash_size__'.freeze
|
19
|
+
|
20
|
+
attr_reader :hash
|
21
|
+
|
22
|
+
def current_hash
|
23
|
+
@hash_stack.last
|
24
|
+
end
|
25
|
+
|
26
|
+
def start_document
|
27
|
+
@hash = {}
|
28
|
+
@hash_stack = [@hash]
|
29
|
+
end
|
30
|
+
|
31
|
+
def end_document
|
32
|
+
raise "Parse stack not empty!" if @hash_stack.size > 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def error(error_message)
|
36
|
+
raise error_message
|
37
|
+
end
|
38
|
+
|
39
|
+
def start_element(uri, name, qname, attrs = [])
|
40
|
+
#puts "START_ELEMENT #{name}"
|
41
|
+
#y attrs
|
42
|
+
new_hash = { CONTENT_KEY => '' }.merge(Hash[attrs])
|
43
|
+
new_hash[HASH_SIZE_KEY] = new_hash.size + 1
|
44
|
+
|
45
|
+
case current_hash[name]
|
46
|
+
when Array then current_hash[name] << new_hash
|
47
|
+
when Hash then current_hash[name] = [current_hash[name], new_hash]
|
48
|
+
when nil then current_hash[name] = new_hash
|
49
|
+
end
|
50
|
+
|
51
|
+
@hash_stack.push(new_hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
def end_element(uri, name, qname)
|
55
|
+
if current_hash.length > current_hash.delete(HASH_SIZE_KEY) && current_hash[CONTENT_KEY].blank? || current_hash[CONTENT_KEY] == ''
|
56
|
+
current_hash.delete(CONTENT_KEY)
|
57
|
+
end
|
58
|
+
@hash_stack.pop
|
59
|
+
end
|
60
|
+
|
61
|
+
def characters(string)
|
62
|
+
return unless string and current_hash[CONTENT_KEY]
|
63
|
+
#puts "CHARACTERS #{string}"
|
64
|
+
current_hash[CONTENT_KEY] << string
|
65
|
+
end
|
66
|
+
|
67
|
+
alias_method :cdata, :characters
|
68
|
+
end
|
69
|
+
|
70
|
+
attr_accessor :document_class
|
71
|
+
self.document_class = HashBuilder
|
72
|
+
|
73
|
+
def parse(data)
|
74
|
+
document = self.document_class.new
|
75
|
+
parser = REXML::Parsers::SAX2Parser.new(data)
|
76
|
+
parser.listen(document)
|
77
|
+
parser.parse
|
78
|
+
document.hash
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ginjo-rfm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 15
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
|
11
|
-
version: 2.0.pre31
|
9
|
+
- 0
|
10
|
+
version: 2.0.0
|
12
11
|
platform: ruby
|
13
12
|
authors:
|
14
13
|
- Geoff Coffey
|
@@ -20,7 +19,7 @@ autorequire:
|
|
20
19
|
bindir: bin
|
21
20
|
cert_chain: []
|
22
21
|
|
23
|
-
date:
|
22
|
+
date: 2012-01-08 00:00:00 Z
|
24
23
|
dependencies:
|
25
24
|
- !ruby/object:Gem::Dependency
|
26
25
|
name: activesupport
|
@@ -39,7 +38,7 @@ dependencies:
|
|
39
38
|
type: :runtime
|
40
39
|
version_requirements: *id001
|
41
40
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
41
|
+
name: activemodel
|
43
42
|
prerelease: false
|
44
43
|
requirement: &id002 !ruby/object:Gem::Requirement
|
45
44
|
none: false
|
@@ -50,7 +49,7 @@ dependencies:
|
|
50
49
|
segments:
|
51
50
|
- 0
|
52
51
|
version: "0"
|
53
|
-
type: :
|
52
|
+
type: :development
|
54
53
|
version_requirements: *id002
|
55
54
|
- !ruby/object:Gem::Dependency
|
56
55
|
name: rake
|
@@ -97,7 +96,7 @@ dependencies:
|
|
97
96
|
type: :development
|
98
97
|
version_requirements: *id005
|
99
98
|
- !ruby/object:Gem::Dependency
|
100
|
-
name:
|
99
|
+
name: diff-lcs
|
101
100
|
prerelease: false
|
102
101
|
requirement: &id006 !ruby/object:Gem::Requirement
|
103
102
|
none: false
|
@@ -111,7 +110,7 @@ dependencies:
|
|
111
110
|
type: :development
|
112
111
|
version_requirements: *id006
|
113
112
|
- !ruby/object:Gem::Dependency
|
114
|
-
name:
|
113
|
+
name: yard
|
115
114
|
prerelease: false
|
116
115
|
requirement: &id007 !ruby/object:Gem::Requirement
|
117
116
|
none: false
|
@@ -125,7 +124,7 @@ dependencies:
|
|
125
124
|
type: :development
|
126
125
|
version_requirements: *id007
|
127
126
|
- !ruby/object:Gem::Dependency
|
128
|
-
name:
|
127
|
+
name: libxml-ruby
|
129
128
|
prerelease: false
|
130
129
|
requirement: &id008 !ruby/object:Gem::Requirement
|
131
130
|
none: false
|
@@ -139,7 +138,7 @@ dependencies:
|
|
139
138
|
type: :development
|
140
139
|
version_requirements: *id008
|
141
140
|
- !ruby/object:Gem::Dependency
|
142
|
-
name:
|
141
|
+
name: nokogiri
|
143
142
|
prerelease: false
|
144
143
|
requirement: &id009 !ruby/object:Gem::Requirement
|
145
144
|
none: false
|
@@ -152,7 +151,35 @@ dependencies:
|
|
152
151
|
version: "0"
|
153
152
|
type: :development
|
154
153
|
version_requirements: *id009
|
155
|
-
|
154
|
+
- !ruby/object:Gem::Dependency
|
155
|
+
name: hpricot
|
156
|
+
prerelease: false
|
157
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
158
|
+
none: false
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
hash: 3
|
163
|
+
segments:
|
164
|
+
- 0
|
165
|
+
version: "0"
|
166
|
+
type: :development
|
167
|
+
version_requirements: *id010
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: ox
|
170
|
+
prerelease: false
|
171
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
172
|
+
none: false
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
hash: 3
|
177
|
+
segments:
|
178
|
+
- 0
|
179
|
+
version: "0"
|
180
|
+
type: :development
|
181
|
+
version_requirements: *id011
|
182
|
+
description: Rfm lets your Ruby scripts and Rails applications talk directly to your Filemaker server. Ginjo-rfm includes ActiveModel compatibility, multiple XML parsers, compound Filemaker find requests, and a configuration API.
|
156
183
|
email: http://groups.google.com/group/rfmcommunity
|
157
184
|
executables: []
|
158
185
|
|
@@ -176,13 +203,15 @@ files:
|
|
176
203
|
- lib/rfm/resultset.rb
|
177
204
|
- lib/rfm/server.rb
|
178
205
|
- lib/rfm/utilities/case_insensitive_hash.rb
|
179
|
-
- lib/rfm/utilities/
|
206
|
+
- lib/rfm/utilities/compound_query.rb
|
180
207
|
- lib/rfm/utilities/config.rb
|
181
208
|
- lib/rfm/utilities/core_ext.rb
|
182
209
|
- lib/rfm/utilities/factory.rb
|
183
210
|
- lib/rfm/utilities/xml_parser.rb
|
184
211
|
- lib/rfm/version.rb
|
185
212
|
- lib/rfm/xml_mini/hpricot.rb
|
213
|
+
- lib/rfm/xml_mini/ox_sax.rb
|
214
|
+
- lib/rfm/xml_mini/rexml_sax.rb
|
186
215
|
- lib/rfm.rb
|
187
216
|
- lib/rfm/VERSION
|
188
217
|
- LICENSE
|
@@ -1,64 +0,0 @@
|
|
1
|
-
module Rfm
|
2
|
-
|
3
|
-
module ComplexQuery # @private :nodoc:
|
4
|
-
# Methods for Rfm::Layout to build complex queries
|
5
|
-
# Perform RFM find using complex boolean logic (multiple value options for a single field)
|
6
|
-
# Mimics creation of multiple find requests for "or" logic
|
7
|
-
# Use: rlayout_object.query({'fieldOne'=>['val1','val2','val3'], 'fieldTwo'=>'someValue', ...})
|
8
|
-
def query(hash_or_recid, options = {})
|
9
|
-
if hash_or_recid.kind_of? Hash
|
10
|
-
get_records('-findquery', assemble_query(hash_or_recid), options)
|
11
|
-
else
|
12
|
-
get_records('-find', {'-recid' => hash_or_recid.to_s}, options)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
# Build ruby params to send to -query action via RFM
|
17
|
-
def assemble_query(query_hash)
|
18
|
-
key_values, query_map = build_key_values(query_hash)
|
19
|
-
key_values.merge("-query"=>query_translate(array_mix(query_map)))
|
20
|
-
end
|
21
|
-
|
22
|
-
# Build key-value definitions and query map '-q1...'
|
23
|
-
def build_key_values(qh)
|
24
|
-
key_values = {}
|
25
|
-
query_map = []
|
26
|
-
counter = 0
|
27
|
-
qh.each_with_index do |ha,i|
|
28
|
-
ha[1] = ha[1].to_a
|
29
|
-
query_tag = []
|
30
|
-
ha[1].each do |v|
|
31
|
-
key_values["-q#{counter}"] = ha[0]
|
32
|
-
key_values["-q#{counter}.value"] = v
|
33
|
-
query_tag << "q#{counter}"
|
34
|
-
counter += 1
|
35
|
-
end
|
36
|
-
query_map << query_tag
|
37
|
-
end
|
38
|
-
return key_values, query_map
|
39
|
-
end
|
40
|
-
|
41
|
-
# Build query request logic for FMP requests '-query...'
|
42
|
-
def array_mix(ary, line=[], rslt=[])
|
43
|
-
ary[0].to_a.each_with_index do |v,i|
|
44
|
-
array_mix(ary[1,ary.size], (line + [v]), rslt)
|
45
|
-
rslt << (line + [v]) if ary.size == 1
|
46
|
-
end
|
47
|
-
return rslt
|
48
|
-
end
|
49
|
-
|
50
|
-
# Translate query request logic to string
|
51
|
-
def query_translate(mixed_ary)
|
52
|
-
rslt = ""
|
53
|
-
sub = mixed_ary.collect {|a| "(#{a.join(',')})"}
|
54
|
-
sub.join(";")
|
55
|
-
end
|
56
|
-
|
57
|
-
end # ComplexQuery
|
58
|
-
|
59
|
-
# class Layout
|
60
|
-
# require 'rfm/layout'
|
61
|
-
# include ComplexQuery
|
62
|
-
# end
|
63
|
-
|
64
|
-
end # Rfm
|