ginjo-rfm 2.0.pre31 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## Ginjo-Rfm 2.0.
|
3
|
+
## Ginjo-Rfm 2.0.0
|
4
4
|
|
5
|
-
*
|
5
|
+
* ActiveModel compatibility allows Rails ActiveRecord-style models
|
6
6
|
|
7
|
-
*
|
7
|
+
* Alternative XML parsers using ActiveSupport::XmlMini interface
|
8
8
|
|
9
|
-
*
|
9
|
+
* Compound queries with multiple omitable find-requests
|
10
10
|
|
11
11
|
* Configuration API manages settings of multiple server/db/layout/etc setups
|
12
12
|
|
data/README.md
CHANGED
@@ -1,37 +1,36 @@
|
|
1
1
|
# ginjo-rfm
|
2
2
|
|
3
|
-
Rfm is a Ruby
|
3
|
+
Rfm is a Ruby-Filemaker adapter, a Ruby gem that allows scripts and applications to exchange commands and data with Filemaker Pro using Filemaker's XML interface. Ginjo-rfm picks up from the lardawge-rfm gem and continues to refine code and fix bugs. Version 2.0 adds some major enhancements, while remaining compatible with ginjo-rfm 1.4.x and lardawge-rfm 1.4.x.
|
4
4
|
|
5
5
|
|
6
6
|
## Documentation & Links
|
7
7
|
|
8
|
-
* Ginjo-rfm rubygem
|
9
|
-
* Original homepage
|
10
|
-
* Rdoc location
|
11
|
-
* Discussion
|
12
|
-
* Ginjo at github
|
13
|
-
* Lardawge at github
|
8
|
+
* Ginjo-rfm rubygem <https://rubygems.org/gems/ginjo-rfm>
|
9
|
+
* Original homepage <http://sixfriedrice.com/wp/products/rfm/>
|
10
|
+
* Rdoc location <http://rubydoc.info/github/ginjo/rfm/frames>
|
11
|
+
* Discussion <http://groups.google.com/group/rfmcommunity>
|
12
|
+
* Ginjo at github <https://github.com/ginjo/rfm>
|
13
|
+
* Lardawge at github <https://github.com/lardawge/rfm>
|
14
14
|
|
15
15
|
|
16
16
|
## New in version 2.0
|
17
17
|
|
18
|
-
|
18
|
+
Ginjo-rfm 2.0 brings new features to Rfm, making it easier than ever to work with Filemaker data from your Ruby scripts.
|
19
|
+
|
20
|
+
* Rails-like modeling with ActiveModel
|
21
|
+
* Support for multiple XML Parsers
|
22
|
+
* Configuration API
|
23
|
+
* Compound Filemaker queries with omitable requests
|
24
|
+
* Full metadata support
|
25
|
+
|
26
|
+
|
27
|
+
### Data Modeling with ActiveModel
|
19
28
|
|
20
29
|
If you can load ActiveModel in your project, you can have model callbacks, validations, and other ActiveModel features.
|
21
30
|
If you can't load ActiveModel (because you're using something incompatible, like Rails 2),
|
22
|
-
you can still use Rfm models... minus callbacks
|
31
|
+
you can still use Rfm models... minus the ActiveModel-specific features like callbacks and validations. Rfm models give you basic
|
23
32
|
data modeling with easy configuration and CRUD features.
|
24
33
|
|
25
|
-
class User < Rfm::Base
|
26
|
-
config :layout => 'user_layout'
|
27
|
-
end
|
28
|
-
|
29
|
-
@user = User.find 12345
|
30
|
-
@user.update_attributes(:name => 'bill', :login => 'admin')
|
31
|
-
@user.save!
|
32
|
-
|
33
|
-
With ActiveModel loaded, you get callbacks, validations, and many other ActiveModel features.
|
34
|
-
|
35
34
|
class User < Rfm::Base
|
36
35
|
config :layout=>'user_layout'
|
37
36
|
before_save :encrypt_password
|
@@ -41,25 +40,13 @@ With ActiveModel loaded, you get callbacks, validations, and many other ActiveMo
|
|
41
40
|
@user = User.new :username => 'bill', :password => 'pass'
|
42
41
|
@user.email = 'my@email.com'
|
43
42
|
@user.save!
|
44
|
-
|
45
|
-
If you prefer, you can create models on-the-fly from any layout.
|
46
43
|
|
47
|
-
my_layout.modelize
|
48
|
-
|
49
|
-
# => MyLayoutName (subclassed from Rfm::Base, represented by your layout's name)
|
50
|
-
|
51
|
-
Or create models for an entire database, all at once.
|
52
44
|
|
53
|
-
|
54
|
-
|
55
|
-
# => [MyLayout, AnotherLayout, ThirdLayout, AndSoOn, ...]
|
56
|
-
|
57
|
-
|
58
|
-
### Choice of XML parsers
|
45
|
+
### Choice of XML Parsers
|
59
46
|
|
60
47
|
Ginjo-rfm 2.0 uses ActiveSupport's XmlMini parsing interface, which has built-in support for
|
61
|
-
LibXML, Nokogiri, and REXML. Additionally, ginjo-rfm includes
|
62
|
-
You can specifiy which parser to use or
|
48
|
+
LibXML, Nokogiri, and REXML. Additionally, ginjo-rfm includes adapters for Ox and Hpricot parsing.
|
49
|
+
You can specifiy which parser to use or let Rfm decide.
|
63
50
|
|
64
51
|
Rfm.config :parser => :libxml
|
65
52
|
|
@@ -74,89 +61,75 @@ Choose your preferred parser globaly, as in the above example, or set a differen
|
|
74
61
|
config :parser => :hpricot
|
75
62
|
end
|
76
63
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
and
|
90
|
-
|
64
|
+
The current parsing options are
|
65
|
+
|
66
|
+
:jdom -> JDOM (for JRuby)
|
67
|
+
:oxsax -> Ox SAX
|
68
|
+
:libxml -> LibXML Tree
|
69
|
+
:libxmlsax -> LibXML SAX
|
70
|
+
:nokogirisax -> Nokogiri SAX
|
71
|
+
:nokogiri -> Nokogiri Tree
|
72
|
+
:hpricot -> Hpricot Tree
|
73
|
+
:rexml -> REXML Tree
|
74
|
+
:rexmlsax -> REXML SAX
|
75
|
+
|
76
|
+
If you're wondering about performance, here are some preliminary benchmark results. Each backend parsed a fmresultset.xml and a FMPXMLLAYOUT.xml 30 times each. Results have differed across environments with different test data, so this data is by no means definitive. Also note that earlier versions of ActiveSupport did not contain all of the parsing backend options mentioned here.
|
77
|
+
|
78
|
+
user system total real
|
79
|
+
ActiveSupport::XmlMini_OxSAX
|
80
|
+
0.200000 0.010000 0.210000 ( 0.211842)
|
81
|
+
ActiveSupport::XmlMini_LibXML
|
82
|
+
0.400000 0.010000 0.410000 ( 0.411823)
|
83
|
+
ActiveSupport::XmlMini_LibXMLSAX
|
84
|
+
0.400000 0.010000 0.410000 ( 0.411360)
|
85
|
+
ActiveSupport::XmlMini_NokogiriSAX
|
86
|
+
0.670000 0.010000 0.680000 ( 0.682885)
|
87
|
+
ActiveSupport::XmlMini_Nokogiri
|
88
|
+
0.970000 0.030000 1.000000 ( 0.998673)
|
89
|
+
ActiveSupport::XmlMini_Hpricot
|
90
|
+
1.950000 0.060000 2.010000 ( 2.011355)
|
91
|
+
ActiveSupport::XmlMini_REXML
|
92
|
+
8.710000 0.180000 8.890000 ( 9.015836)
|
93
|
+
ActiveSupport::XmlMini_REXMLSAX
|
94
|
+
6.320000 0.040000 6.360000 ( 6.377179)
|
91
95
|
|
92
|
-
For simple applications, put all of your configuration in a top-level hash, RFM_CONFIG,
|
93
|
-
and let Rfm do the rest. For more complicated setups, use configuration subgroups,
|
94
|
-
and/or set configuration on-the-fly when you create Server, Database, Layout, or Base objects.
|
95
96
|
|
96
|
-
Use RFM_CONFIG
|
97
97
|
|
98
|
-
|
99
|
-
:host => 'main_host',
|
100
|
-
:database => 'main_database',
|
101
|
-
:account_name => 'myname',
|
102
|
-
:password => 'somepass',
|
103
|
-
:second_server => {
|
104
|
-
:host => 'second_host',
|
105
|
-
:database => 'second_database'
|
106
|
-
}
|
98
|
+
### Configuration API
|
107
99
|
|
108
|
-
|
100
|
+
The ginjo-rfm configuration module lets you store your settings in several different ways. Store some, or all, of your project-specific settings in a rfm.yml file at the root of your project, or in your Rails config/ directory. Settings can also be put in a RFM_CONFIG constant at the top level of your project. Configuration settings can be simple key=>values, or they can be named groups of key=>values. Configuration can also be passed to various Rfm methods during load and runtime, as individual settings or as groups.
|
109
101
|
|
110
|
-
|
111
|
-
:database => 'main_database',
|
112
|
-
:account_name => 'myname',
|
113
|
-
:password => 'somepass',
|
114
|
-
:second_server => {
|
115
|
-
:host => 'second_host',
|
116
|
-
:database => 'second_database'
|
117
|
-
}
|
118
|
-
|
119
|
-
Set configuration of RFM::Base
|
102
|
+
rfm.yml
|
120
103
|
|
121
|
-
|
104
|
+
:ssl: true
|
105
|
+
:root_cert: false
|
106
|
+
:timeout: 10
|
107
|
+
:port: 443
|
108
|
+
:host: live.mydomain.com
|
109
|
+
:account_name: admin
|
110
|
+
:password: pass
|
111
|
+
:database: MyFmDb
|
122
112
|
|
123
|
-
Set a model's configuration
|
113
|
+
Set a model's configuration.
|
124
114
|
|
125
|
-
class
|
126
|
-
config :
|
115
|
+
class MyModel < Rfm::Base
|
116
|
+
config :layout => 'mylayout'
|
127
117
|
end
|
128
|
-
|
129
|
-
View model-specific configuration
|
130
|
-
|
131
|
-
MyClass.config
|
132
|
-
|
133
|
-
# => {:host => 'second_host', :database => 'second_database'}
|
134
118
|
|
135
|
-
View the merged configurations of all relevent levels in the configuration chain.
|
136
|
-
|
137
|
-
MyClass.get_config
|
138
|
-
|
139
|
-
# => {:host => 'second_host', :database => 'second_database', :account_name => 'myname', :password => 'somepass', :ssl => true}
|
140
119
|
|
120
|
+
### Compound Filemaker Queries, with Omitable FMP Find Requests
|
141
121
|
|
142
|
-
|
122
|
+
Create a Filemaker 'omit' request by including an :omit key with a value of true.
|
143
123
|
|
144
|
-
|
145
|
-
* Rfm::Config # top-level config module
|
146
|
-
* Rfm::Factory # where server, database, and layout objects are managed
|
147
|
-
* Rfm::Base # master modeling class
|
148
|
-
* MyModel # custom modeling class
|
124
|
+
my_layout.find :field1 => 'val1', :field2 => 'val2', :omit => true
|
149
125
|
|
126
|
+
Create multiple Filemaker find requests by passing an array of hashes to the #find method.
|
150
127
|
|
128
|
+
my_layout.find [{:field1 => 'bill', :field2 => 'admin'}, {:field2 => 'staff', :field3 => 'inactive', :omit => true}, ...]
|
151
129
|
|
130
|
+
If the value of a field in a find request is an array of strings, the string values will be logically OR'd in the query.
|
152
131
|
|
153
|
-
|
154
|
-
|
155
|
-
Create queries with mixed boolean logic, mimicing Filemaker's multiple-request find.
|
156
|
-
|
157
|
-
layout.query :fieldOne => ['=val1','>=val2','<val3'], :fieldTwo =>'someValue'
|
158
|
-
|
159
|
-
This will create 3 "find requests" (in a single call to FM Server), one for each value in the fieldOne array, AND'd with the fieldTwo value.
|
132
|
+
my_layout.find :fieldOne => ['bill','mike','bob'], :fieldTwo =>'staff'
|
160
133
|
|
161
134
|
|
162
135
|
### Full Metadata Support
|
@@ -167,16 +140,10 @@ This will create 3 "find requests" (in a single call to FM Server), one for each
|
|
167
140
|
* Layout fields
|
168
141
|
* Layout portals
|
169
142
|
* Resultset meta
|
170
|
-
* Field meta
|
171
|
-
* Portal meta
|
172
|
-
|
173
|
-
From ginjo-rfm 1.4.x, the following enhancements are also included.
|
143
|
+
* Field definition meta
|
144
|
+
* Portal definition meta
|
174
145
|
|
175
|
-
|
176
|
-
|
177
|
-
* Value-list alternate display
|
178
|
-
|
179
|
-
There are also many enhancements to make it easier than ever to get the objects or data you want. Some examples:
|
146
|
+
There are also many enhancements to make it easier to get the objects or data you want. Some examples:
|
180
147
|
|
181
148
|
Get a database object using default config
|
182
149
|
|
@@ -197,23 +164,49 @@ Get the portal names (table-occurence names) on the current layout
|
|
197
164
|
Get the names of fields on the current layout
|
198
165
|
|
199
166
|
my_record.field_names
|
167
|
+
|
168
|
+
### From ginjo-rfm 1.4.x
|
169
|
+
|
170
|
+
From ginjo-rfm 1.4.x, the following features are also included.
|
171
|
+
|
172
|
+
Connection timeout settings
|
173
|
+
|
174
|
+
Rfm.config :timeout => 10
|
175
|
+
|
176
|
+
Value-list alternate display
|
177
|
+
|
178
|
+
i = array_of_value_list_items[3] # => '8765'
|
179
|
+
i.value # => '8765'
|
180
|
+
i.display # => '8765 Amy'
|
181
|
+
|
200
182
|
|
201
183
|
### Compatibility
|
202
184
|
|
203
|
-
Ginjo-rfm 2.0 is compatible with previous versions of Rfm - Ginjo, Lardawge, and SFR. However, much has been changed in the low-level workings of the code
|
185
|
+
Ginjo-rfm 2.0 is compatible with previous versions of Rfm - Ginjo, Lardawge, and SFR. However, much has been changed in the low-level workings of the code. If you have scripts that reach deep into the guts of Rfm 1.0 thru 1.4.x, you may find that some things are slightly different in 2.0. Additionally, some long-standing bugs have been fixed that may have been so de rigeur, that the "correct behavior" in Rfm 2.0 may break scripts that relied on the previously buggy functions. These low level changes, and the addition of major new functionality, led the decision to release this version of Rfm as 2.0, instead of 1.5.
|
186
|
+
|
187
|
+
|
188
|
+
## Download & Installation
|
189
|
+
|
190
|
+
There are at least 4 ways to download ginjo-rfm.
|
204
191
|
|
192
|
+
* With Bundler: gem 'ginjo-rfm'
|
193
|
+
* With the command line: gem install ginjo-rfm
|
194
|
+
* From https://rubygems.org/gems/ginjo-rfm
|
195
|
+
* From https://github.com/ginjo/rfm
|
205
196
|
|
206
|
-
|
197
|
+
Ginjo-rfm requires the ActiveSupport gem for several features, including XML parsing. Rfm has been tested and works with ActiveSupport 2.3.5 thru 3.1.3, on both ruby 1.8.7 and ruby 1.9.2. ActiveModel requires ActiveSupport 3+ and is not compatible with ActiveSupport 2.3.x. So while you CAN use ginjo-rfm with Rails 2.3, you will not have ActiveModel features like callbacks and validations. Basic modeling functionality and Filemaker interaction will continue to work, unaffected by the presence or absence of ActiveModel.
|
207
198
|
|
208
|
-
Ginjo-rfm
|
199
|
+
For the best performance, it is recommended that you use the Ox, Libxml-ruby, Nokogiri, or Hpricot parser. Ginjo-rfm does not require these gems by dependency, so you will have to make sure they are installed on your machine and/or specified in your Gemfile, if you wish to use them. If you don't want to install any of these parsers, Rfm will use the REXML parser included with the Ruby standard library. Similarly, ginjo-rfm does not require ActiveModel by dependency, so also make sure that is installed and/or specified in your Gemfile if you wish to use ActiveModel features.
|
200
|
+
|
201
|
+
Note that the installation of Ox, Libxml-ruby, Nokogiri, or Hpricot gems will require further dependencies. Please see the install instructions for each parser to get them installed and running on your system.
|
209
202
|
|
210
|
-
To get the best performance, it is recommended that you use the LibXML or Nokogiri parser. Ginjo-rfm does not require these gems by dependency, so you will have to make sure they are installed on your machine and/or specified in your Gemfile, if you wish to use them. Similarly, ginjo-rfm does not require ActiveModel by dependency, so also make sure that is installed and/or specified in your Gemfile, if you wish to use ActiveModel features.
|
211
203
|
|
212
204
|
### Using Bundler and/or Rails >= 3.0
|
213
205
|
|
214
|
-
In
|
206
|
+
In your Gemfile:
|
215
207
|
|
216
208
|
gem 'ginjo-rfm'
|
209
|
+
gem 'ox' # optional
|
217
210
|
gem 'libxml-ruby' # optional
|
218
211
|
gem 'nokogiri' # optional
|
219
212
|
gem 'hpricot' # optional
|
@@ -234,6 +227,7 @@ If you are not using Bundler, Rfm will pick up the XML parsers and ActiveModel a
|
|
234
227
|
In your shell:
|
235
228
|
|
236
229
|
gem install ginjo-rfm
|
230
|
+
gem install ox # optional
|
237
231
|
gem install nokogiri # optional
|
238
232
|
gem install libxml-ruby # optional
|
239
233
|
gem install hpricot # optional
|
@@ -245,55 +239,251 @@ Once the gem is installed, you can use rfm in your ruby scripts by requiring it:
|
|
245
239
|
require 'rfm'
|
246
240
|
|
247
241
|
|
248
|
-
|
249
242
|
### Edge - in an upcoming version of ginjo-rfm
|
250
243
|
|
251
244
|
Try out unreleased features of ginjo-rfm in the edge branch.
|
252
245
|
|
253
246
|
#gemfile
|
254
247
|
gem 'ginjo-rfm', :git=>'git://github.com/ginjo/rfm.git', :branch=>'edge'
|
255
|
-
|
256
|
-
|
257
248
|
|
258
|
-
## Basic usage
|
259
249
|
|
260
|
-
|
250
|
+
|
251
|
+
## Ginjo-rfm Basic Usage
|
252
|
+
|
253
|
+
The first step in getting connected to your Filemaker databases with Rfm is to store your configuration settings in a yaml file or in the RFM_CONFIG hash. The second step is creating a model that represents a layout from one of your Filemaker databases.
|
254
|
+
|
255
|
+
### Configuration
|
256
|
+
|
257
|
+
In previous versions of Rfm, you may have stored your configuration settings in a variable or constant, then passed those settings to Rfm::Server.new(MY_SETTINGS). Now you can put your configuration settings in a rfm.yml file at the root of your project or in your project's config/ directory, and Rfm will use those settings automatically when building your Model's Server, Database, and Layout objects.
|
258
|
+
|
259
|
+
rfm.yml
|
260
|
+
|
261
|
+
:ssl: true
|
262
|
+
:root_cert: false
|
263
|
+
:timeout: 10
|
264
|
+
:port: 443
|
265
|
+
:host: my.host.com
|
266
|
+
:account_name: myname
|
267
|
+
:password: somepass
|
268
|
+
:database: MyFmDb
|
269
|
+
|
270
|
+
Or put your configuration settings in a hash called RFM_CONFIG. Rfm will pick those up just as with the yaml file.
|
261
271
|
|
262
272
|
RFM_CONFIG = {
|
263
|
-
:host => '
|
264
|
-
:database => '
|
273
|
+
:host => 'my.host.com',
|
274
|
+
:database => 'MyFmDb',
|
265
275
|
:account_name => 'myname',
|
266
276
|
:password => 'somepass',
|
267
|
-
:ssl =>
|
268
|
-
:
|
269
|
-
|
270
|
-
|
277
|
+
:ssl => true,
|
278
|
+
:root_cert => false,
|
279
|
+
:port => 443,
|
280
|
+
:timeout => 10
|
271
281
|
}
|
272
282
|
|
273
|
-
|
283
|
+
You can use configuration subgroups to seperate global settings from environment-specific settings.
|
284
|
+
|
285
|
+
:ssl: true
|
286
|
+
:root_cert: false
|
287
|
+
:timeout: 10
|
288
|
+
:port: 443
|
289
|
+
:development:
|
290
|
+
:host: dev.mydomain.com
|
291
|
+
:account_name: admin
|
292
|
+
:password: pass
|
293
|
+
:database: DevFmDb
|
294
|
+
:production:
|
295
|
+
:host: live.mydomain.com
|
296
|
+
:account_name: admin
|
297
|
+
:password: pass
|
298
|
+
:database: LiveFmDb
|
299
|
+
|
300
|
+
Then in your environment files (or wherever you put environment-specific configuration in your ruby project),
|
301
|
+
specifiy which subgroup to use.
|
302
|
+
|
303
|
+
RFM_CONFIG = {:use => :development}
|
304
|
+
|
305
|
+
You can use configuration subgroups to contain any arbitrary groups of settings.
|
306
|
+
|
307
|
+
:ssl: true
|
308
|
+
:root_cert: false
|
309
|
+
:timeout: 10
|
310
|
+
:port: 443
|
311
|
+
:customer1:
|
312
|
+
:host: customer1.com
|
313
|
+
:account_name: cust1
|
314
|
+
:password: pass
|
315
|
+
:database: custOneFmDb
|
316
|
+
:customer2:
|
317
|
+
:host: customer2.com
|
318
|
+
:account_name: cust2
|
319
|
+
:password: pass
|
320
|
+
:database: custTwoFmDb
|
321
|
+
|
322
|
+
Use the configuration setting method `config` to set configuration for specific objects, like Rfm models. When you pass a `:use => :subgroup` to the `config` method, you're saying use that subgroup of settings.
|
323
|
+
|
324
|
+
class MyModel < Rfm::Base
|
325
|
+
config :use => :customer1, :layout => 'some_layout'
|
326
|
+
end
|
327
|
+
|
328
|
+
The current heirarchy of configurable objects in Rfm, starting at the top, is:
|
329
|
+
|
330
|
+
* rfm.yml # file of settings in yaml format
|
331
|
+
* RFM_CONFIG # user-defined hash
|
332
|
+
* Rfm::Config # top-level config module, inherits settings from RFM_CONFIG and rfm.yml
|
333
|
+
* Rfm::Factory # where server, database, and layout objects are managed, inherits settings from Rfm::Config
|
334
|
+
* Rfm::Base # master modeling class, inherits settings from Rfm::Config
|
335
|
+
* MyModel # sublcassed custom modeling class, inherits settings from Rfm::Base
|
274
336
|
|
337
|
+
You can also include or extend the Rfm::Config module in any object in your project to gain Rfm configuration abilities for that object.
|
338
|
+
|
339
|
+
module MyModule
|
340
|
+
include Rfm::Config
|
341
|
+
config :host => 'myhost.com', :database => 'mydb', :account_name => 'name', :password => 'pass'
|
342
|
+
# inherits settings from Rfm::Config by default
|
343
|
+
end
|
344
|
+
|
345
|
+
class Person < Rfm::Base
|
346
|
+
config :parent => MyModule, :layout => 'some_layout'
|
347
|
+
# using :parent to set where this object inherits config settings from
|
348
|
+
end
|
349
|
+
|
350
|
+
Use `get_config` to view the compiled configuration settings for any object. Configuration compilation will start at the top (rfm.yml), then work down the heirarchy of objects to wherever you call the `get_config` method, merging in all global settings along the way. Subgroupings of settings will also be merged, if they are specified in a subgroup filter. A subgroup filter occurs any time you put `:use => :subgroup` in your configuration setting. You can have multiple subgroup filters, and when configuration compilation occurs, all subgroup filters are stacked up into an array and processed in order (as if you typed `:use=>[:subgroup1, :subgroup2, subgroup3, ...]` which is also allowed). `get_config` returns a compiled configuration hash, leaving all configuration settings in all modules and classes un-touched.
|
351
|
+
|
352
|
+
Person.get_config
|
353
|
+
|
354
|
+
# => {:ssl => true, :timeout => 10, :root_cert => false, :port => 443,
|
355
|
+
:host => 'myhost', :database => 'mydb', :layout => 'some_layout',
|
356
|
+
:account_name => 'name', :password => 'pass'
|
357
|
+
}
|
358
|
+
|
359
|
+
#### Possible Configuration Options
|
360
|
+
|
361
|
+
Following are all of the recognized configuration options, including defaults if applicable.
|
362
|
+
|
363
|
+
:host => 'localhost'
|
364
|
+
:port => 80
|
365
|
+
:ssl => true
|
366
|
+
:root_cert => true
|
367
|
+
:root_cert_name => ''
|
368
|
+
:root_cert_path => '/'
|
369
|
+
:account_name => ''
|
370
|
+
:password => ''
|
371
|
+
:log_actions => false
|
372
|
+
:log_responses => false
|
373
|
+
:log_parser => false
|
374
|
+
:warn_on_redirect => true
|
375
|
+
:raise_on_401 => false
|
376
|
+
:timeout => 60
|
377
|
+
|
378
|
+
:use # use configuration subgroups, or filter configuration subgoups
|
379
|
+
:layout # specify the name of the layout to use
|
380
|
+
:parent => 'Rfm::Config' # the parent configuration object of the current configuration object, as string
|
381
|
+
:file_name => 'rfm.yml # name of configuration file to load yaml from
|
382
|
+
:file_path => ['', 'config/'] # array of additional file paths to look for configuration file
|
383
|
+
:parser => ActiveSupport::XmlMini_REXML # XmlParser to use if no other is specified or can be found
|
384
|
+
|
275
385
|
|
276
|
-
###
|
386
|
+
### Using Models
|
277
387
|
|
278
|
-
Rfm models provide easy access
|
388
|
+
Rfm models provide easy access, modeling, and persistence of your Filemaker data.h
|
279
389
|
|
280
390
|
class User < Rfm::Base
|
281
|
-
config :layout => '
|
391
|
+
config :layout => 'my_user_layout'
|
392
|
+
attr_accessor :password
|
282
393
|
end
|
283
394
|
|
284
395
|
@user = User.new(:login => 'bill', :password => 'xxxxxxxx', :email => 'my@email.com')
|
396
|
+
@user.encrypt_password
|
285
397
|
@user.save!
|
286
398
|
|
287
|
-
@user.
|
288
|
-
# => '
|
399
|
+
@user.record_id
|
400
|
+
# => '12345'
|
289
401
|
|
290
402
|
@user.field_names
|
291
403
|
# => ['login', 'encryptedPassword', 'email', 'groups', 'lastLogin' ]
|
292
404
|
|
293
|
-
User.
|
294
|
-
# =>
|
405
|
+
User.total_count
|
406
|
+
# => 35467
|
407
|
+
|
408
|
+
@user = User.find 12345
|
409
|
+
@user.update_attributes(:login => 'william', :email => 'myother@email.com')
|
410
|
+
@user.save!
|
411
|
+
|
412
|
+
Put your model code anywhere at the top level of your script/application. In Rails, this could be your initialization file(s), your environment file(s), or in a file in your Models directory called something like `rfm_models.rb`. Then require 'rfm_models' in your initialization or environment.
|
413
|
+
|
414
|
+
rfm_models.rb
|
415
|
+
|
416
|
+
require 'rfm'
|
417
|
+
|
418
|
+
class User < Rfm::Base
|
419
|
+
config :layout => 'user_layout'
|
420
|
+
end
|
421
|
+
|
422
|
+
class Order < Rfm::Base
|
423
|
+
config :layout => 'order_layout'
|
424
|
+
end
|
425
|
+
|
426
|
+
main_initializer.rb
|
427
|
+
|
428
|
+
require 'rfm_models'
|
429
|
+
|
430
|
+
|
431
|
+
If you prefer, you can create models on-the-fly from any layout.
|
432
|
+
|
433
|
+
my_rfm_layout_object.modelize
|
434
|
+
|
435
|
+
# => MyLayoutName (subclassed from Rfm::Base, represented by your layout's name)
|
436
|
+
|
437
|
+
Or create models for an entire database, all at once.
|
438
|
+
|
439
|
+
Rfm.modelize /_xml/i, 'my_database', :my_config_group
|
440
|
+
|
441
|
+
# => [MyLayoutXml, AnotherLayoutXml, ThirdLayoutXml, AndSoOnXml, ...]
|
442
|
+
# The regex in the first parameter is optional and filters the layout names in the specified database.
|
443
|
+
# Omit the regex parameter to modelize all possible layouts in the specified database.
|
444
|
+
|
445
|
+
With ActiveModel loaded, you get callbacks, validations, errors, serialization, and a handful of other features extracted from Rails ActiveRecord.
|
446
|
+
|
447
|
+
In your Gemfile
|
448
|
+
|
449
|
+
gem 'activemodel'
|
450
|
+
|
451
|
+
Or without Bundler
|
452
|
+
|
453
|
+
require 'active_model'
|
454
|
+
|
455
|
+
Then use ActiveModel features in your Rfm models
|
456
|
+
|
457
|
+
class MyModel < Rfm::Base
|
458
|
+
before_create :encrypt_password
|
459
|
+
after_validate "puts 'yay!'"
|
460
|
+
validates :email, :presence => true
|
461
|
+
end
|
462
|
+
|
463
|
+
@my_model = MyModel.new
|
464
|
+
@my_model.valid?
|
465
|
+
@my_model.save!
|
466
|
+
@my_model.errors
|
467
|
+
|
468
|
+
To learn more about ActiveModel, see the ActiveModel or RubyOnRails documentation:
|
469
|
+
|
470
|
+
* <http://rubydoc.info/gems/activemodel/frames>
|
471
|
+
* <http://api.rubyonrails.org/>
|
472
|
+
* <http://guides.rubyonrails.org/active_record_validations_callbacks.html>
|
473
|
+
|
474
|
+
Once you have an Rfm model or layout, you can use any of the standard Rfm commands to create, search, edit, and delete records. To learn more about these commands, see below for Databases, Layouts, Resultsets, and Records. Or checkout the API documentation for Rfm::Server, Rfm::Database, Rfm::Layout, Rfm::Record, and Rfm::Base.
|
475
|
+
|
476
|
+
#### Two Small Changes in Rfm Return Values
|
295
477
|
|
296
|
-
|
478
|
+
When using Models to retrieve records using the `any` method or the `find(record_id)` method, the return values will be single Rfm::Record objects. This differs from the traditional Rfm behavior of these methods when accessed directly from the the Rfm::Layout instance, where the return value is always a Rfm::Resultset.
|
479
|
+
|
480
|
+
MyModel.find(record_id) == my_layout.find(record_id)[0]
|
481
|
+
MyModel.any == my_layout.any[0]
|
482
|
+
|
483
|
+
|
484
|
+
### Getting Rfm Server, Database, and Layout Objects Manually
|
485
|
+
|
486
|
+
Well... not entirely manually. To get server, db, and layout objects as in previous versions of Rfm, see the section "Working with classic Rfm features". Ginjo-rfm 2.0 has some new methods to create/locate Filemaker objects and meta data. Many of these new methods are configuration-aware.
|
297
487
|
|
298
488
|
Create a layout object using default configuration settings.
|
299
489
|
|
@@ -305,18 +495,76 @@ Create a layout object using a subgroup of configuration settings.
|
|
305
495
|
|
306
496
|
Create a layout object passing in a layout name, multiple config subgroups to merge, and specific settings.
|
307
497
|
|
308
|
-
my_layout = Rfm.layout 'layout_name', :
|
498
|
+
my_layout = Rfm.layout 'layout_name', :other_server, :log_actions => true
|
499
|
+
|
500
|
+
The same can be done for servers and databases.
|
501
|
+
|
502
|
+
my_server = Rfm.server 'my.host.com'
|
503
|
+
my_database = Rfm.database :development, :ssl => false, :root_cert => false
|
504
|
+
my_database = Rfm.db :production
|
505
|
+
# db and database are interchangeable aliases in Ginjo-rfm 2.0
|
506
|
+
|
507
|
+
You can query your Filemaker objects for the familiar meta-data.
|
508
|
+
|
509
|
+
my_server.databases.all.names
|
510
|
+
my_server.databases['MyFmDb']
|
511
|
+
my_database.layouts
|
512
|
+
my_layout.value_lists
|
513
|
+
my_layout.field_names
|
514
|
+
my_layout.portal_meta
|
309
515
|
|
516
|
+
Here are two new fun Layout methods:
|
310
517
|
|
311
|
-
|
518
|
+
my_layout.total_count # => total records in table
|
519
|
+
my_layout.count(:some_field => 'search criteria', ...) # Returns foundset_count only, no records.
|
312
520
|
|
521
|
+
See the API documentation for the lowdown on new methods in Rfm Server, Database, and Layout objects.
|
522
|
+
|
523
|
+
### Shortcuts, Tips & Tricks
|
524
|
+
|
525
|
+
All Rfm methods that take a configuration hash have two possible shortcuts.
|
526
|
+
|
527
|
+
If you pass a symbol before the hash, it is interpreted as subgroup specification or subgroup filter
|
528
|
+
|
529
|
+
config :mygroup, :layout => 'mylayout'
|
530
|
+
# :use => :mygroup, :layout => 'mylayout'
|
531
|
+
|
532
|
+
get_config :othergroup
|
533
|
+
# :use => [:mygroup, :othergroup], :layout => 'mylayout'
|
534
|
+
|
535
|
+
If you pass a string before any symbols or hashes, it is interepreted as one of several possible configuration settings - usually a layout name, a database name, or a server hostname. The interpretation is dependent on the method being called. Not all methods will make use of a string parameter.
|
536
|
+
|
537
|
+
class MyModel < Rfm::Base
|
538
|
+
config 'MyLayoutName'
|
539
|
+
# :layout => 'MyLayoutName'
|
540
|
+
end
|
541
|
+
|
542
|
+
Rfm.database 'MyDatabaseName'
|
543
|
+
# :database => 'MyDatabaseName'
|
544
|
+
|
545
|
+
Rfm.modelize 'MyDatabaseName', :group1
|
546
|
+
# :database => 'MyDatabaseName', :use => :group1
|
547
|
+
|
548
|
+
Just about anything you can do with a Rfm layout, you can also do with a Rfm model.
|
549
|
+
|
550
|
+
MyModel.total_count
|
551
|
+
MyModel.field_names
|
552
|
+
MyModel.database.name
|
553
|
+
|
554
|
+
There are a number of methods within Rfm that have been made accessible from the top-level Rfm module. Note that the server/database/layout methods are new to Rfm and are not the same as Rfm::Server, Rfm::Database, and Rfm::Layout. See the above section on "Getting Rfm Server, Database, and Layout Objects Manually" for an overview of how to use the new server/database/layout methods.
|
555
|
+
|
556
|
+
# Any of these methods can be assed via Rfm.<method_name>
|
557
|
+
|
558
|
+
Rfm::Factory :servers, :server, :db, :database, :layout, :models, :modelize
|
559
|
+
Rfm::XmlParser :backend, :backend=
|
560
|
+
Rfm::Config :config, :get_config, :config_clear
|
313
561
|
|
314
|
-
|
562
|
+
## Working with "Classic" Rfm Features
|
315
563
|
|
316
|
-
All of Rfm's original features and functions are available as they were before, though some low-level functionality has changed slightly.
|
564
|
+
All of Rfm's original features and functions are available as they were before, though some low-level functionality has changed slightly. See the documentation for each module & class for the specifics on low-level methods and functionality.
|
317
565
|
|
318
566
|
|
319
|
-
|
567
|
+
### Connecting
|
320
568
|
|
321
569
|
IMPORTANT:SSL and Certificate verification are on by default. Please see Server#new in rdocs for explanation and setup.
|
322
570
|
You connect with the Rfm::Server object. This little buddy will be your window into FileMaker data.
|
@@ -341,7 +589,7 @@ if your web publishing engine runs on a port other than 80, you can provide the
|
|
341
589
|
:root_cert => false
|
342
590
|
)
|
343
591
|
|
344
|
-
|
592
|
+
### Databases and Layouts
|
345
593
|
|
346
594
|
All access to data in FileMaker's XML interface is done through layouts, and layouts live in databases. The Rfm::Server object has a collection of databases called 'db'. So to get ahold of a database called "My Database", you can do this:
|
347
595
|
|
@@ -371,7 +619,7 @@ Bringing it all together, you can do this to go straight from a server to a spec
|
|
371
619
|
|
372
620
|
my_layout = my_server["My Database"]["My Layout"]
|
373
621
|
|
374
|
-
|
622
|
+
### Working with Layouts
|
375
623
|
|
376
624
|
Once you have a layout object, you can start doing some real work. To get every record from the layout:
|
377
625
|
|
@@ -414,7 +662,7 @@ For a complete list of the available options, see the "expand_options" method in
|
|
414
662
|
Finally, if filemaker returns an error when executing any of these methods, an error will be raised in your ruby script. There is one exception to this, though. If a find results in no records being found (FileMaker error # 401) I just ignore it and return you a ResultSet with zero records in it. If you prefer an error in this case, add :raise_on_401 => true to the options you pass the Rfm::Server when you create it.
|
415
663
|
|
416
664
|
|
417
|
-
|
665
|
+
### ResultSet and Record Objects
|
418
666
|
|
419
667
|
Any method on the Layout object that returns data will return a ResultSet object. Rfm::Result::ResultSet is a subclass of Array, so first and foremost, you can use it like any other array:
|
420
668
|
|
@@ -486,7 +734,7 @@ Again, you can string things together with Ruby. This will calculate the total d
|
|
486
734
|
total = 0.0
|
487
735
|
my_order.portals["Line Items"].each {|line| total += line.quantity * line.price}
|
488
736
|
|
489
|
-
|
737
|
+
### Data Types
|
490
738
|
|
491
739
|
FileMaker's field types are coerced to Ruby types thusly:
|
492
740
|
|
@@ -509,7 +757,7 @@ Finally, container fields will come back as URI objects. You can:
|
|
509
757
|
|
510
758
|
Specifically, the URI refers to the _contents_ of the container field. When accessed, the file, picture, or movie in the field will be downloaded.
|
511
759
|
|
512
|
-
|
760
|
+
### Troubleshooting
|
513
761
|
|
514
762
|
There are two cheesy methods to help track down problems. When you create a server object, you can provide two additional optional parameters:
|
515
763
|
|
@@ -541,6 +789,4 @@ Other lead contributors:
|
|
541
789
|
* Jesse Antunes helped ensure that Rfm is stable and functional.
|
542
790
|
* Larry Sprock added ssl support, switched the xml parser to a much faster Nokogiri, added the rspec testing framework, and refined code architecture.
|
543
791
|
|
544
|
-
## Copyright
|
545
792
|
|
546
|
-
Copyright (c) 2007 Six Fried Rice, LLC and Mufaddal Khumr. See LICENSE for details.
|