lardawge-rfm 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rfm.rb CHANGED
@@ -1,241 +1,19 @@
1
- # RFM provides easy access to FileMaker Pro data. With it, Ruby scripts can
2
- # perform finds, read records and fields, update data, and perform scripts using
3
- # a simple ruby-like syntax.
4
- #
5
- # Author:: Geoff Coffey (mailto:gwcoffey@gmail.com)
6
- # Copyright:: Copyright (c) 2007 Six Fried Rice, LLC and Mufaddal Khumri
7
- # License:: See MIT-LICENSE for details
8
- #
9
- # RFM uses the FileMaker XML API, so it requires:
10
- # - FileMaker Server 9.0 or later
11
- # - or FileMaker Server Advanced 7.0 or later
12
- #
13
- # This documentation serves as a reference to the classes in the API. For more complete
14
- # usage documentation, see the RFM home page at http://sixfriedrice.com/wp/products/rfm/
15
- #
16
- # = Quick Start
17
- #
18
- # Rfm is a Gem. As such, any ruby file that uses it, needs to have these two lines on top:
19
- #
20
- # require "rubygems"
21
- # require "rfm"
22
- #
23
- # (If you don't have Rfm installed, use the +gem install rfm+ command to get it.)
24
- #
25
- # === Get a Server
26
- #
27
- # Everything in Rfm starts with the Server object. You create a Server object like this:
28
- #
29
- # myServer = Rfm::Server.new(
30
- # :host => "yourhost",
31
- # :account_name => "someone",
32
- # :pasword => "secret"
33
- # )
34
- #
35
- # The Server object supports many other options, which you'll find explained in its
36
- # documentation.
37
- #
38
- # Note: The account name and password are optional. You can instead provide them on
39
- # a per-database basis (using Database::account_name and Database::password). But
40
- # it is convenient to do it here because you often have one set of credentials
41
- # across all databases. Also, you must provide an account_name and password if you
42
- # want to ask the server for a list of available databases.
43
- #
44
- # === Get a Database
45
- #
46
- # Once you have a Server object, you can use it to get a Database. For example, if your
47
- # database is called "Customers", you get it like this:
48
- #
49
- # myDatabase = myServer["Customers"]
50
- #
51
- # If you need to supply account and password info specifically for this database
52
- # (rather than doing it at the Server level), do this:
53
- #
54
- # myDatabase.account_name = "someone"
55
- # myDatabase.password = "secret"
56
- #
57
- # *IMPORTANT NOTE:* The account name you use to access FileMaker must have the
58
- # +fmxml+ extended privilege. In other words, edit its privilege set and turn on
59
- # "Access via XML Web Publishing (fmxml)" in the Extended Privileges section
60
- # at the bottom-left of the Edit Privilege Set window. If you don't do this,
61
- # Rfm will report that it can't log in.
62
- #
63
- # === Get a Layout
64
- #
65
- # Every action you send to FileMaker always goes through a layout. This is how Rfm knows
66
- # which table you want to work with, and which fields on that table you care about. This
67
- # should feel pretty familiar now:
68
- #
69
- # myLayout = myDatabase["Details"]
70
- #
71
- # You might use layouts you already have, or make new layout just for Rfm. Just remember that
72
- # if you delete a layout, or remove a field from a layout that your Rfm code uses, the
73
- # code will stop working.
74
- #
75
- # === Putting it Together
76
- #
77
- # Usually you don't care much about the intermediate Database object (it's a gateway object,
78
- # if you will). So it is often easiest to combine all the above steps like this:
79
- #
80
- # myLayout = myServer["Customers"]["Details"]
81
- #
82
- # === Performing Actions
83
- #
84
- # The Layout object can do a lot of things (see its documentation for a full list). But
85
- # in general, it involves records. For instance, you can find records:
86
- #
87
- # result = myLayout.find({"First Name" => "Bill"})
88
- #
89
- # That code finds everybody whose first name in Bill. All the Layout methods return an
90
- # ResultSet object. It contains the records, as well as metadata about the fields and
91
- # portals on the layout. Usually you'll only concern yourself with the records (and you
92
- # can read about the others in the ResultSet documentation).
93
- #
94
- # ResultSet is a subclass of Array, Ruby's built in array type. So you can treate it just
95
- # like any other array:
96
- #
97
- # first_record = result[0]
98
- # a_few_records = result[3,7]
99
- # record_count = result.size
100
- #
101
- # But usually you'll want to loop through them all. Because this is an array, you can use
102
- # code that is familiar to any Ruby whiz:
103
- #
104
- # result.each { |record|
105
- # # do something with record here
106
- # }
107
- #
108
- # === Working with Records
109
- #
110
- # The records in a ResultSet are actually Record objects. They hold the actual data from
111
- # FileMaker. Record subclasses Hash, another built in Ruby type, so you can use them like
112
- # this:
113
- #
114
- # full_name = record["First Name"] + ' ' + record["Last Name"]
115
- # info.merge(record)
116
- # record.each_value { |value| puts value }
117
- # if record.value?("Bill") then puts "Bill is in there somewhere"
118
- #
119
- # The field name serves as the hash key, so these examples get fields called First Name and
120
- # Last Name. (Note: Unlike a typical Ruby hash, Record objects are not case sensitive. You
121
- # can say +record["first name"]+ or +record["FIRST NAME"]+ and it will still work.)
122
- #
123
- # A record object has the power to save changes to itself back to the database. For example:
124
- #
125
- # records.each { |record|
126
- # record["First Name"] = record["First Name"].upcase
127
- # record.save
128
- # }
129
- #
130
- # That concise code converts the First Name field to all uppercase in every record in the
131
- # ResultSet. Note that each time you call Record::save, if the record has been modified,
132
- # Rfm has to send an action to FileMaker. A loop like the one above will be quite slow
133
- # across many records. There is not fast way to update lots of records at once right now,
134
- # although you might be able to accomplish it with a FileMaker script by passing a
135
- # parameter).
136
- #
137
- # === Editing and Deleting Records
138
- #
139
- # Any time you edit or delete a record, you *must* provide the record's internal record
140
- # if. This is not the value in any field. Rather, it is the ID FileMaker assigns to the
141
- # record internally. So an edit or delete is almost always a two-step process:
142
- #
143
- # record = myLayout.find({"Customer ID" => "1234"})[0]
144
- # myLayout.edit(record.record_id, {"First Name" => "Steve"})
145
- #
146
- # The code above first finds a Customer record. It then uses the Record::record_id method
147
- # to discover that record's internal id. That id is passed to the Layout::edit method.
148
- # The edit method also accepts a hash of record changes. In this case, we're changing
149
- # the value in the First Name field to "Steve".
150
- #
151
- # Also, note the [0] on the end of the first line. A find _always_ returns a ResultSet.
152
- # If there's only one record, it is still in an array. This array just happens to have only
153
- # one element. The [0] pulls out that single record.
154
- #
155
- # To delete a record, you would do this instead:
156
- #
157
- # record = myLayout.find({"Customer ID" => "1234"})[0]
158
- # myLayout.delete(record.record_id)
159
- #
160
- # Finally, the Layout::find method can also find a record using its internal id:
161
- #
162
- # record = myLayout.find(some_id)
163
- #
164
- # If the parameter you pass to Layout::find is not a hash, it is converted to a string
165
- # and assumed to be a record id.
166
- #
167
- # === Performing Scripts
168
- #
169
- # Rfm can run a script in conjunction with any other action. For example, you might want
170
- # to find a set of records, then run a script on them all. Or you may want to run a script
171
- # when you delete a record. Here's how:
172
- #
173
- # myLayout.find({"First Name" => "Bill"}, {:post_script => "Process Sales"})
174
- #
175
- # This code finds every record with "Bill" in the First Name field, then runs the script
176
- # called "Process Sales." You can control when the script actually runs, as explained in
177
- # the documentation for Common Options for the Layout class.
178
- #
179
- # You can also pass a parameter to the script when it runs. Here's the deal:
180
- #
181
- # myLayout.find(
182
- # {"First Name" => "Bill"},
183
- # {:post_script => ["Process Sales", "all"]}
184
- # )
185
- #
186
- # This time, the text value "all" is passed to the script as a script parameter.
187
- #
188
- # =Notes on Rfm with Ruby on Rails
189
- #
190
- # Rfm is a great fit for Rails. But it isn't ActiveRecord, so you need to do things
191
- # a little differently.
192
- #
193
- # === Configuration
194
- #
195
- # To avoid having to reconfigure your Server object in every Rails action, you
196
- # might add a configuration hash to the environment.rb. It can include all the
197
- # options you need to connecto to your server:
198
- #
199
- # RFM_CONFIG = {
200
- # :host => "yourhost",
201
- # :account_name => "someone",
202
- # :password => "secret",
203
- # :db => "Customers"
204
- # }
205
- #
206
- # Then you can get a server concisely:
207
- #
208
- # myServer = Server.net(RFM_CONFIG)
209
- # myServer[RFM_CONFIG[:db]]["My Layout"]...
210
- #
211
- # You might even want to add code to your application.rb to centralize access
212
- # to your various layouts.
213
- #
214
- # === Disable ActiveRecord
215
- #
216
- # If you're not using any SQL database in your Rails app, you'll quickly discover
217
- # that Rails insists on a SQL database configuration anyway. This is easy to fix.
218
- # Just turn off ActiveRecord. In the environment.rb, find the line that starts with
219
- # +config.frameworks+. This is where you can disable the parts of Rails you're not
220
- # using. Uncomment the line and make it look like this:
221
- #
222
- # config.frameworks -= [ :active_record ]
223
- #
224
- # Now Rails will no longer insist on a SQL database.
225
1
  path = File.expand_path(File.dirname(__FILE__))
226
2
  $:.unshift(path) unless $:.include?(path)
227
3
 
4
+ require path + '/rfm/utilities/case_insensitive_hash'
5
+ require path + '/rfm/utilities/factory'
6
+
228
7
  module Rfm
229
8
 
230
- autoload :Error, "rfm/error"
231
- autoload :Factory, "rfm/factory"
232
- autoload :Result, "rfm/result"
233
- autoload :Utility, "rfm/utility"
234
-
235
- autoload :Database, 'rfm/commands/database'
236
- autoload :FieldControl, 'rfm/commands/field_control'
237
- autoload :Layout, 'rfm/commands/layout'
238
- autoload :Script, 'rfm/commands/script'
239
- autoload :Server, 'rfm/commands/server'
9
+ class CommunicationError < StandardError; end
10
+ class ParameterError < StandardError; end
11
+ class AuthenticationError < StandardError; end
12
+
13
+ autoload :Error, 'rfm/error'
14
+ autoload :Server, 'rfm/server'
15
+ autoload :Database, 'rfm/database'
16
+ autoload :Layout, 'rfm/layout'
17
+ autoload :Resultset, 'rfm/resultset'
240
18
 
241
19
  end
@@ -0,0 +1,69 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module Rfm
4
+ err_module = Error
5
+ describe err_module do
6
+ describe ".lookup" do
7
+
8
+ it "should return a default system error if input code is 0" do
9
+ error = err_module.getError(0)
10
+ error.message.should eql('SystemError occurred: (FileMaker Error #0)')
11
+ error.code.should eql(0)
12
+ end
13
+
14
+ it "should return a default system error if input code is 22" do
15
+ error = err_module.getError(20)
16
+ error.message.should eql('SystemError occurred: (FileMaker Error #20)')
17
+ error.code.should eql(20)
18
+ end
19
+
20
+ it "should return a custom message as second argument" do
21
+ error = err_module.getError(104, 'Custom Message Here.')
22
+ error.message.should match(/Custom Message Here/)
23
+ end
24
+
25
+ it "should return a script missing error" do
26
+ error = err_module.getError(104)
27
+ error.message.should eql('ScriptMissingError occurred: (FileMaker Error #104)')
28
+ error.code.should eql(104)
29
+ end
30
+
31
+ it "should return a range validation error" do
32
+ error = err_module.getError(503)
33
+ error.message.should eql('RangeValidationError occurred: (FileMaker Error #503)')
34
+ error.code.should eql(503)
35
+ end
36
+
37
+ it "should return unknown error if code not found" do
38
+ error = err_module.getError(-1)
39
+ error.message.should eql('UnknownError occurred: (FileMaker Error #-1)')
40
+ error.code.should eql(-1)
41
+ error.class.should eql(Error::UnknownError)
42
+ end
43
+
44
+ end
45
+
46
+ describe ".find_by_code" do
47
+ it "should return a constant representing the error class" do
48
+ constant = err_module.find_by_code(503)
49
+ constant.should eql(err_module::RangeValidationError)
50
+ end
51
+ end
52
+
53
+ describe ".build_message" do
54
+ before(:each) do
55
+ @message = err_module.build_message(503, 'This is a custom message')
56
+ end
57
+
58
+ it "should return a string with the code and message included" do
59
+ @message.should match(/This is a custom message/)
60
+ @message.should match(/503/)
61
+ end
62
+
63
+ it "should look like" do
64
+ @message.should eql('503 occurred: (FileMaker Error #This is a custom message)')
65
+ end
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rfm'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lardawge-rfm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ hash: 5
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 4
9
+ - 1
10
+ version: 1.4.1
5
11
  platform: ruby
6
12
  authors:
7
13
  - Geoff Coffey
@@ -12,20 +18,24 @@ autorequire:
12
18
  bindir: bin
13
19
  cert_chain: []
14
20
 
15
- date: 2009-12-19 00:00:00 -05:00
21
+ date: 2010-06-28 00:00:00 -07:00
16
22
  default_executable:
17
23
  dependencies:
18
24
  - !ruby/object:Gem::Dependency
19
25
  name: nokogiri
20
- type: :runtime
21
- version_requirement:
22
- version_requirements: !ruby/object:Gem::Requirement
26
+ prerelease: false
27
+ requirement: &id001 !ruby/object:Gem::Requirement
28
+ none: false
23
29
  requirements:
24
30
  - - ">="
25
31
  - !ruby/object:Gem::Version
32
+ hash: 3
33
+ segments:
34
+ - 0
26
35
  version: "0"
27
- version:
28
- description: Rfm brings your FileMaker data to Ruby with elegance and speed. Now your Ruby scripts and Rails applications can talk directly to your FileMaker server with a syntax that just feels right.
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ description: Rfm brings your FileMaker data to Ruby. Now your Ruby scripts and Rails applications can talk directly to your FileMaker server.
29
39
  email: http://groups.google.com/group/rfmcommunity
30
40
  executables: []
31
41
 
@@ -36,17 +46,20 @@ extra_rdoc_files:
36
46
  - README.rdoc
37
47
  files:
38
48
  - lib/rfm.rb
39
- - lib/rfm/commands/database.rb
40
- - lib/rfm/commands/field_control.rb
41
- - lib/rfm/commands/layout.rb
42
- - lib/rfm/commands/script.rb
43
- - lib/rfm/commands/server.rb
49
+ - lib/rfm/database.rb
44
50
  - lib/rfm/error.rb
45
- - lib/rfm/factory.rb
46
- - lib/rfm/result.rb
47
- - lib/rfm/utility.rb
51
+ - lib/rfm/layout.rb
52
+ - lib/rfm/metadata/field.rb
53
+ - lib/rfm/metadata/script.rb
54
+ - lib/rfm/record.rb
55
+ - lib/rfm/resultset.rb
56
+ - lib/rfm/server.rb
57
+ - lib/rfm/utilities/case_insensitive_hash.rb
58
+ - lib/rfm/utilities/factory.rb
48
59
  - LICENSE
49
60
  - README.rdoc
61
+ - spec/rfm/error_spec.rb
62
+ - spec/spec_helper.rb
50
63
  has_rdoc: true
51
64
  homepage: http://sixfriedrice.com/wp/products/rfm/
52
65
  licenses: []
@@ -59,23 +72,30 @@ rdoc_options:
59
72
  require_paths:
60
73
  - lib
61
74
  required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
62
76
  requirements:
63
77
  - - ">="
64
78
  - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
65
82
  version: "0"
66
- version:
67
83
  required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
68
85
  requirements:
69
86
  - - ">="
70
87
  - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
71
91
  version: "0"
72
- version:
73
92
  requirements: []
74
93
 
75
94
  rubyforge_project:
76
- rubygems_version: 1.3.5
95
+ rubygems_version: 1.3.7
77
96
  signing_key:
78
97
  specification_version: 3
79
- summary: FileMaker to Ruby adapter
98
+ summary: Ruby to Filemaker adapter
80
99
  test_files:
81
- - test/errors_test.rb
100
+ - spec/rfm/error_spec.rb
101
+ - spec/spec_helper.rb
@@ -1,50 +0,0 @@
1
- module Rfm
2
- # The FieldControl object represents a field on a FileMaker layout. You can find out what field
3
- # style the field uses, and the value list attached to it.
4
- #
5
- # =Attributes
6
- #
7
- # * *name* is the name of the field
8
- #
9
- # * *style* is any one of:
10
- # * * :edit_box - a normal editable field
11
- # * * :scrollable - an editable field with scroll bar
12
- # * * :popup_menu - a pop-up menu
13
- # * * :checkbox_set - a set of checkboxes
14
- # * * :radio_button_set - a set of radio buttons
15
- # * * :popup_list - a pop-up list
16
- # * * :calendar - a pop-up calendar
17
- #
18
- # * *value_list_name* is the name of the attached value list, if any
19
- #
20
- # * *value_list* is an array of strings representing the value list items, or nil
21
- # if this field has no attached value list
22
- class FieldControl
23
- def initialize(name, style, value_list_name, value_list)
24
- @name = name
25
- case style
26
- when "EDITTEXT"
27
- @style = :edit_box
28
- when "POPUPMENU"
29
- @style = :popup_menu
30
- when "CHECKBOX"
31
- @style = :checkbox_set
32
- when "RADIOBUTTONS"
33
- @style = :radio_button_set
34
- when "POPUPLIST"
35
- @style = :popup_list
36
- when "CALENDAR"
37
- @style = :calendar
38
- when "SCROLLTEXT"
39
- @style = :scrollable
40
- else
41
- nil
42
- end
43
- @value_list_name = value_list_name
44
- @value_list = value_list
45
- end
46
-
47
- attr_reader :name, :style, :value_list_name, :value_list
48
-
49
- end
50
- end
@@ -1,18 +0,0 @@
1
- module Rfm
2
- # The Script object represents a FileMaker script. At this point, the Script object exists only so
3
- # you can enumrate all scripts in a Database (which is a rare need):
4
- #
5
- # myDatabase.script.each {|script|
6
- # puts script.name
7
- # }
8
- #
9
- # If you want to _run_ a script, see the Layout object instead.
10
- class Script
11
- def initialize(name, db)
12
- @name = name
13
- @db = db
14
- end
15
-
16
- attr_reader :name
17
- end
18
- end