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.
- data/CHANGELOG.md +107 -0
 - data/README.md +378 -133
 - data/lib/rfm.rb +51 -19
 - data/lib/rfm/VERSION +1 -1
 - data/lib/rfm/base.rb +416 -0
 - data/lib/rfm/database.rb +14 -9
 - data/lib/rfm/layout.rb +148 -96
 - data/lib/rfm/metadata/field.rb +5 -5
 - data/lib/rfm/metadata/field_control.rb +52 -51
 - data/lib/rfm/metadata/script.rb +7 -5
 - data/lib/rfm/record.rb +71 -56
 - data/lib/rfm/resultset.rb +45 -26
 - data/lib/rfm/server.rb +21 -17
 - data/lib/rfm/utilities/complex_query.rb +64 -0
 - data/lib/rfm/utilities/config.rb +115 -0
 - data/lib/rfm/utilities/core_ext.rb +90 -0
 - data/lib/rfm/utilities/factory.rb +100 -17
 - data/lib/rfm/utilities/xml_parser.rb +94 -0
 - data/lib/rfm/version.rb +1 -1
 - data/lib/rfm/xml_mini/hpricot.rb +133 -0
 - metadata +87 -30
 
    
        data/CHANGELOG.md
    ADDED
    
    | 
         @@ -0,0 +1,107 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Changelog
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ## Ginjo-Rfm 2.0.pre
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            * Alternative XML parsers using ActiveSupport::XmlMini interface
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            * ActiveModel compatibility allows Rails-like models
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            * Complex queries with Layout#query method
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            * Configuration API manages settings of multiple server/db/layout/etc setups
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            * Full Filemaker metadata support
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            ## Ginjo-Rfm 1.4.4
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            * Fixed bug when creating empty value list.
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            * Additional fixes for Rfm::VERSION.
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            * Fixed Record getter/setter issue.
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            * Other minor fixes and cleanup.
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            * Added tests to rspec.
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            * Documentation cleanup.
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            ## Ginjo-Rfm 1.4.3
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            * Fixed version management issue. Rfm::VERSION now works.
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            ## Ginjo-Rfm 1.4.2
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            * Re-implemented:  
         
     | 
| 
      
 36 
     | 
    
         
            +
              
         
     | 
| 
      
 37 
     | 
    
         
            +
            	Layout#field_controls
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            	Layout#value_lists  
         
     | 
| 
      
 40 
     | 
    
         
            +
              
         
     | 
| 
      
 41 
     | 
    
         
            +
            * Enhanced:  
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            	ValueListItem handles both display & data items now.
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            	Timeout feature from timting (github/timting/rfm).
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            	Added specs for Record#save.  
         
     | 
| 
      
 48 
     | 
    
         
            +
              
         
     | 
| 
      
 49 
     | 
    
         
            +
            * Fixed:  
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            	[Bug] Getting & setting fields with symbol-based keys was producing error.
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            	[Bug] Setting fields would not update main record hash.
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            	[Bug] Record#save wasn't merging back into self.  
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            * Partial Fix:  
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            	server.db.all
         
     | 
| 
      
 60 
     | 
    
         
            +
            	db.layout.all
         
     | 
| 
      
 61 
     | 
    
         
            +
            	db.script.all  
         
     | 
| 
      
 62 
     | 
    
         
            +
              
         
     | 
| 
      
 63 
     | 
    
         
            +
            	Note: the "#all" method returns object names (as keys) only. The receiver of the method maintains the full object collection.  
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            	Example:  
         
     | 
| 
      
 66 
     | 
    
         
            +
              
         
     | 
| 
      
 67 
     | 
    
         
            +
            	    server.db.all #=> ['dbname1', 'dbname2', ...]
         
     | 
| 
      
 68 
     | 
    
         
            +
            	    server.db     #=> a DbFactory object (descendant of Hash), containing 0 or more Database objects
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            ## Lardawge-Rfm 1.4.2 (unreleased)
         
     | 
| 
      
 71 
     | 
    
         
            +
              
         
     | 
| 
      
 72 
     | 
    
         
            +
            * Made nil default on fields with no value.  
         
     | 
| 
      
 73 
     | 
    
         
            +
              
         
     | 
| 
      
 74 
     | 
    
         
            +
            	Example:
         
     | 
| 
      
 75 
     | 
    
         
            +
             
         
     | 
| 
      
 76 
     | 
    
         
            +
            	    Old: record.john #=> "" 
         
     | 
| 
      
 77 
     | 
    
         
            +
            	    New: record.john #=> nil
         
     | 
| 
      
 78 
     | 
    
         
            +
               
         
     | 
| 
      
 79 
     | 
    
         
            +
            ## Lardawge-Rfm 1.4.1.2
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            * [Bug] Pointing out why testing is soooooo important when refactoring... Found a bug in getter/setter method in Rfm::Record (yes, added spec for it).
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            ## Lardawge-Rfm 1.4.1.1
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            * [Bug] Inadvertently left out an attr_reader for server from resultset effecting container urls.
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            ## Lardawge-Rfm 1.4.1*
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            * Changed Server#do_action to Server#connect.
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            * XML Parsing is now done via xpath which significantly speeds up parsing.
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            * Changes to accessor method names for Resultset#portals Resultset#fields to Resultset#portal_meta and Resultset#field_meta to better describe what you get back.
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            * Added an option to load portal records which defaults to false. This significantly speeds up load time when portals are present on the layout.
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
            	Example:  
         
     | 
| 
      
 98 
     | 
    
         
            +
              
         
     | 
| 
      
 99 
     | 
    
         
            +
            	    result = fm_server('layout').find({:username => "==#{username}"}, {:include_portals => true})
         
     | 
| 
      
 100 
     | 
    
         
            +
            	    # => This will fetch all records with portal records attached.
         
     | 
| 
      
 101 
     | 
    
         
            +
              
         
     | 
| 
      
 102 
     | 
    
         
            +
            	    result.first.portals
         
     | 
| 
      
 103 
     | 
    
         
            +
            	    # => would return an empty hash by default.
         
     | 
| 
      
 104 
     | 
    
         
            +
                
         
     | 
| 
      
 105 
     | 
    
         
            +
            * Internal file restructuring. Some classes have changed but it should be nothing a developer would use API wise. Please let me know if it is.
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
            * Removed Layout#value_lists && Layout#field_controls. Will put back in if the demand is high. Needs a major refactor and different placement if it goes back in. Was broken so it didn't seem to be used by many devs.
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,180 +1,413 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # ginjo-rfm
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       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.  
     | 
| 
      
 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 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            ## Documentation & Links
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 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 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            ## New in version 2.0
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            ### Data modeling with ActiveModel and graceful degradation without ActiveModel.
         
     | 
| 
      
 19 
     | 
    
         
            +
            	
         
     | 
| 
      
 20 
     | 
    
         
            +
            If you can load ActiveModel in your project, you can have model callbacks, validations, and other ActiveModel features.
         
     | 
| 
      
 21 
     | 
    
         
            +
            If you can't load ActiveModel (because you're using something incompatible, like Rails 2),
         
     | 
| 
      
 22 
     | 
    
         
            +
            you can still use Rfm models... minus callbacks & validations. Rfm models give you basic
         
     | 
| 
      
 23 
     | 
    
         
            +
            data modeling with easy configuration and CRUD features.
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 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 
     | 
    
         
            +
            	  class User < Rfm::Base
         
     | 
| 
      
 36 
     | 
    
         
            +
            	    config      :layout=>'user_layout'
         
     | 
| 
      
 37 
     | 
    
         
            +
            	    before_save :encrypt_password
         
     | 
| 
      
 38 
     | 
    
         
            +
            	    validate    :valid_email_address
         
     | 
| 
      
 39 
     | 
    
         
            +
            	  end
         
     | 
| 
      
 40 
     | 
    
         
            +
            	
         
     | 
| 
      
 41 
     | 
    
         
            +
            	  @user = User.new :username => 'bill', :password => 'pass'
         
     | 
| 
      
 42 
     | 
    
         
            +
            	  @user.email = 'my@email.com'
         
     | 
| 
      
 43 
     | 
    
         
            +
            	  @user.save!
         
     | 
| 
      
 44 
     | 
    
         
            +
            	
         
     | 
| 
      
 45 
     | 
    
         
            +
            If you prefer, you can create models on-the-fly from any layout.
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 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 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            	  Rfm.modelize :my_db_name_or_config
         
     | 
| 
      
 54 
     | 
    
         
            +
            	  
         
     | 
| 
      
 55 
     | 
    
         
            +
            	  # => [MyLayout, AnotherLayout, ThirdLayout, AndSoOn, ...]
         
     | 
| 
      
 56 
     | 
    
         
            +
            	
         
     | 
| 
      
 57 
     | 
    
         
            +
              
         
     | 
| 
      
 58 
     | 
    
         
            +
            ### Choice of XML parsers
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            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 a module for Hpricot parsing.
         
     | 
| 
      
 62 
     | 
    
         
            +
            You can specifiy which parser to use or load them all and let Rfm decide.
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            	  Rfm.config :parser => :libxml
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            If you're not able to install one of the faster parsers, ginjo-rfm will fall back to
         
     | 
| 
      
 67 
     | 
    
         
            +
            ruby's built-in REXML. Want to roll your own XML adapter? Just pass it to Rfm as a module.
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            	  Rfm.config :parser => MyHomeGrownAdapter
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            Choose your preferred parser globaly, as in the above example, or set a different parser for each model.
         
     | 
| 
      
 72 
     | 
    
         
            +
            		
         
     | 
| 
      
 73 
     | 
    
         
            +
            	  class Order < Rfm::Base
         
     | 
| 
      
 74 
     | 
    
         
            +
            	    config :parser => :hpricot
         
     | 
| 
      
 75 
     | 
    
         
            +
            	  end
         
     | 
| 
      
 76 
     | 
    
         
            +
            	
         
     | 
| 
      
 77 
     | 
    
         
            +
            Not only do you have 4 XML backend parsers to choose from, but you also have the option of choosing from different parsing shemes - the DOM parsing scheme, or the streaming (SAX or SAX-like) scheme. This gives you six different available parsing possilities.
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
            * LibXML DOM
         
     | 
| 
      
 80 
     | 
    
         
            +
            * LibXML SAX
         
     | 
| 
      
 81 
     | 
    
         
            +
            * Nokogiri DOM
         
     | 
| 
      
 82 
     | 
    
         
            +
            * Nokogiri SAX
         
     | 
| 
      
 83 
     | 
    
         
            +
            * Hpricot DOM
         
     | 
| 
      
 84 
     | 
    
         
            +
            * REXML DOM
         
     | 
| 
       4 
85 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
      
 86 
     | 
    
         
            +
            ### Configuration API
         
     | 
| 
       6 
87 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
      
 88 
     | 
    
         
            +
            The ginjo-rfm configuration module is a heirarchical system that allows you to configure settings at a global level
         
     | 
| 
      
 89 
     | 
    
         
            +
            and then recall just the settings you need, where you need them. Configuration settings can be simple
         
     | 
| 
      
 90 
     | 
    
         
            +
            values, or they can be named groups of values.
         
     | 
| 
       8 
91 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            * Larry Sprock added ssl support, switched the xml parser to a much faster Nokogiri, added the rspec testing framework, and refactored the code to pave way for future development.
         
     | 
| 
      
 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.
         
     | 
| 
       13 
95 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
      
 96 
     | 
    
         
            +
            Use RFM_CONFIG
         
     | 
| 
       15 
97 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
      
 98 
     | 
    
         
            +
            	   RFM_CONFIG = {
         
     | 
| 
      
 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 
     | 
    
         
            +
            	     }
         
     | 
| 
       22 
107 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
      
 108 
     | 
    
         
            +
            Or set global configuration with the 'config' method
         
     | 
| 
       24 
109 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 110 
     | 
    
         
            +
            	  Rfm.config :host => 'main_host',
         
     | 
| 
      
 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
         
     | 
| 
       30 
120 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
      
 121 
     | 
    
         
            +
            	   Rfm::Base.config :ssl => true
         
     | 
| 
       32 
122 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
      
 123 
     | 
    
         
            +
            Set a model's configuration
         
     | 
| 
      
 124 
     | 
    
         
            +
            	
         
     | 
| 
      
 125 
     | 
    
         
            +
            	   class MyClass < Rfm::Base
         
     | 
| 
      
 126 
     | 
    
         
            +
            	     config :second_server, :layout => 'mylayout'
         
     | 
| 
      
 127 
     | 
    
         
            +
            	   end
         
     | 
| 
      
 128 
     | 
    
         
            +
            	
         
     | 
| 
      
 129 
     | 
    
         
            +
            View	model-specific configuration
         
     | 
| 
      
 130 
     | 
    
         
            +
               
         
     | 
| 
      
 131 
     | 
    
         
            +
            	   MyClass.config
         
     | 
| 
      
 132 
     | 
    
         
            +
            	
         
     | 
| 
      
 133 
     | 
    
         
            +
            	   # =>  {:host => 'second_host', :database => 'second_database'}
         
     | 
| 
       37 
134 
     | 
    
         | 
| 
      
 135 
     | 
    
         
            +
            View the merged configurations of all relevent levels in the configuration chain.
         
     | 
| 
       38 
136 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
      
 137 
     | 
    
         
            +
            	   MyClass.get_config
         
     | 
| 
      
 138 
     | 
    
         
            +
            	   
         
     | 
| 
      
 139 
     | 
    
         
            +
            	   # => {:host => 'second_host', :database => 'second_database', :account_name => 'myname', :password => 'somepass', :ssl => true}
         
     | 
| 
       40 
140 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
            Rfm depends on Nokogiri gem, which installs executables requiring C compilation. Make sure you have a C compiler installed, ruby development headers, and Nokogiri's pre-requisite libxml2 & libxslt (or Xcode on OS X). For help installing [Nokogiri](http://nokogiri.org/), see their helpful [tutorial](http://nokogiri.org/tutorials/installing_nokogiri.html). Future versions of ginjo-rfm will offer alternative XML parsing options, hopefully making it easier to get up and running.
         
     | 
| 
       42 
141 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 142 
     | 
    
         
            +
            Calling the get_config method will show you what compilation of config settings are seen at any given point in Rfm and/or in your application. The current heirarchy of configurable objects in Rfm, starting at the top:
         
     | 
| 
       44 
143 
     | 
    
         | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
      
 144 
     | 
    
         
            +
            * RFM_CONFIG   # a user-defined hash
         
     | 
| 
      
 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
         
     | 
| 
       47 
149 
     | 
    
         | 
| 
       48 
     | 
    
         
            -
            Once the gem is installed, you can use rfm in your ruby scripts by requiring it:
         
     | 
| 
       49 
150 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
                require 'rubygems'
         
     | 
| 
       51 
     | 
    
         
            -
                require 'rfm'
         
     | 
| 
       52 
151 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
            ### Complex Queries
         
     | 
| 
      
 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.
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
            ### Full Metadata Support
         
     | 
| 
      
 163 
     | 
    
         
            +
            	
         
     | 
| 
      
 164 
     | 
    
         
            +
            * Server databases
         
     | 
| 
      
 165 
     | 
    
         
            +
            * Database layouts
         
     | 
| 
      
 166 
     | 
    
         
            +
            * Database scripts
         
     | 
| 
      
 167 
     | 
    
         
            +
            * Layout fields
         
     | 
| 
      
 168 
     | 
    
         
            +
            * Layout portals
         
     | 
| 
      
 169 
     | 
    
         
            +
            * Resultset meta
         
     | 
| 
      
 170 
     | 
    
         
            +
            * Field meta
         
     | 
| 
      
 171 
     | 
    
         
            +
            * Portal meta
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
            From ginjo-rfm 1.4.x, the following enhancements are also included.
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
            * Connection timeout settings
         
     | 
| 
      
 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:
         
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
      
 181 
     | 
    
         
            +
            Get a database object using default config
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
            	  Rfm.db 'my_db'
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
            Get a layout object using config grouping :my_group
         
     | 
| 
      
 186 
     | 
    
         
            +
            	
         
     | 
| 
      
 187 
     | 
    
         
            +
            	  Rfm.layout :my_group
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
            Get the total count of all records in the table
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
            	  MyModel.total_count
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
            Get the portal names (table-occurence names) on the current layout
         
     | 
| 
      
 194 
     | 
    
         
            +
             
     | 
| 
      
 195 
     | 
    
         
            +
            	  MyModel.portal_names
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
            Get the names of fields on the current layout
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
            	  my_record.field_names
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
            ### Compatibility
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 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, in orer to pave the way for data modeling and flexible XML adapters. 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.
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
            Ginjo-rfm requires ActiveSupport for several features, including XML parsing. Rfm has been tested and works with ActiveSupport 2.3.5 thru 3.1.3. 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 model functionality and Filemaker interaction will continue to work, unaffected by the presence or absence of ActiveModel.
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 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 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
            ### Using Bundler and/or Rails >= 3.0
         
     | 
| 
       54 
213 
     | 
    
         | 
| 
       55 
214 
     | 
    
         
             
            In the Gemfile:
         
     | 
| 
       56 
215 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
      
 216 
     | 
    
         
            +
            	   gem 'ginjo-rfm'
         
     | 
| 
      
 217 
     | 
    
         
            +
            	   gem 'libxml-ruby' # optional
         
     | 
| 
      
 218 
     | 
    
         
            +
            	   gem 'nokogiri'    # optional
         
     | 
| 
      
 219 
     | 
    
         
            +
            	   gem 'hpricot'     # optional
         
     | 
| 
      
 220 
     | 
    
         
            +
            	   gem 'activemodel' # optional
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
            In your shell:
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
            	   bundle install
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
            In your project, you may or may not have to require 'rfm', depending on Bundler's configuration:
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
            	   require 'rfm'
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
            ### Without Bundler
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
            If you are not using Bundler, Rfm will pick up the XML parsers and ActiveModel as long as they are available in your current rubygems installation.
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
            In your shell:
         
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
            	   gem install ginjo-rfm
         
     | 
| 
      
 237 
     | 
    
         
            +
            	   gem install nokogiri     # optional
         
     | 
| 
      
 238 
     | 
    
         
            +
            	   gem install libxml-ruby  # optional
         
     | 
| 
      
 239 
     | 
    
         
            +
            	   gem install hpricot      # optional
         
     | 
| 
      
 240 
     | 
    
         
            +
            	   gem install activemodel  # optional
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
            Once the gem is installed, you can use rfm in your ruby scripts by requiring it:
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
            	   require 'rubygems'
         
     | 
| 
      
 245 
     | 
    
         
            +
            	   require 'rfm'
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
       58 
248 
     | 
    
         | 
| 
       59 
249 
     | 
    
         
             
            ### Edge - in an upcoming version of ginjo-rfm
         
     | 
| 
       60 
250 
     | 
    
         | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
      
 251 
     | 
    
         
            +
            Try out unreleased features of ginjo-rfm in the edge branch.
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
            	   #gemfile
         
     | 
| 
      
 254 
     | 
    
         
            +
            	   gem 'ginjo-rfm', :git=>'git://github.com/ginjo/rfm.git', :branch=>'edge'
         
     | 
| 
      
 255 
     | 
    
         
            +
               
         
     | 
| 
      
 256 
     | 
    
         
            +
               
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
            ## Basic usage
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
            Put your configuration settings in a hash represented by RFM_CONFIG. This will make it easier to get and use objects in Rfm.
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
            	   RFM_CONFIG = {
         
     | 
| 
      
 263 
     | 
    
         
            +
            	     :host          => 'main_host',
         
     | 
| 
      
 264 
     | 
    
         
            +
            	     :database      => 'main_database',
         
     | 
| 
      
 265 
     | 
    
         
            +
            	     :account_name  => 'myname',
         
     | 
| 
      
 266 
     | 
    
         
            +
            	     :password      => 'somepass',
         
     | 
| 
      
 267 
     | 
    
         
            +
            	     :ssl           => false,
         
     | 
| 
      
 268 
     | 
    
         
            +
            	     :second_server => {
         
     | 
| 
      
 269 
     | 
    
         
            +
            	       :host        => 'second_host',
         
     | 
| 
      
 270 
     | 
    
         
            +
            	       :database    => 'second_database'
         
     | 
| 
      
 271 
     | 
    
         
            +
            	     }
         
     | 
| 
      
 272 
     | 
    
         
            +
             
     | 
| 
      
 273 
     | 
    
         
            +
            Then you have two easy ways to access your layouts - and your data.
         
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
            ### With models
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
            Rfm models provide easy access to the record-finder functions of Rfm layouts, and they give us a way to easily persist objects to the database.
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
            	   class User < Rfm::Base
         
     | 
| 
      
 281 
     | 
    
         
            +
            	     config :layout => 'my_layout_name'
         
     | 
| 
      
 282 
     | 
    
         
            +
            	   end
         
     | 
| 
      
 283 
     | 
    
         
            +
            	
         
     | 
| 
      
 284 
     | 
    
         
            +
            	   @user = User.new(:login => 'bill', :password => 'xxxxxxxx', :email => 'my@email.com')
         
     | 
| 
      
 285 
     | 
    
         
            +
            	   @user.save!
         
     | 
| 
      
 286 
     | 
    
         
            +
            	
         
     | 
| 
      
 287 
     | 
    
         
            +
            	   @user.login
         
     | 
| 
      
 288 
     | 
    
         
            +
            	   # => 'bill'
         
     | 
| 
      
 289 
     | 
    
         
            +
             
     | 
| 
      
 290 
     | 
    
         
            +
            	   @user.field_names
         
     | 
| 
      
 291 
     | 
    
         
            +
            	   # => ['login', 'encryptedPassword', 'email', 'groups', 'lastLogin' ]
         
     | 
| 
      
 292 
     | 
    
         
            +
            	
         
     | 
| 
      
 293 
     | 
    
         
            +
            	   User.field_names
         
     | 
| 
      
 294 
     | 
    
         
            +
            	   # => ['login', 'encryptedPassword', 'email', 'groups', 'lastLogin' ]
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
            ### Manually
         
     | 
| 
      
 297 
     | 
    
         
            +
             
     | 
| 
      
 298 
     | 
    
         
            +
            Create a layout object using default configuration settings.
         
     | 
| 
      
 299 
     | 
    
         
            +
             
     | 
| 
      
 300 
     | 
    
         
            +
            	   my_layout = Rfm.layout 'layout_name'
         
     | 
| 
      
 301 
     | 
    
         
            +
            	
         
     | 
| 
      
 302 
     | 
    
         
            +
            Create a layout object using a subgroup of configuration settings.
         
     | 
| 
      
 303 
     | 
    
         
            +
             
     | 
| 
      
 304 
     | 
    
         
            +
            	   my_layout = Rfm.layout :subgroup_name
         
     | 
| 
      
 305 
     | 
    
         
            +
            	
         
     | 
| 
      
 306 
     | 
    
         
            +
            Create a layout object passing in a layout name, multiple config subgroups to merge, and specific settings.
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
      
 308 
     | 
    
         
            +
            	   my_layout = Rfm.layout 'layout_name', :second_server, :log_actions => true
         
     | 
| 
      
 309 
     | 
    
         
            +
             
     | 
| 
      
 310 
     | 
    
         
            +
             
     | 
| 
      
 311 
     | 
    
         
            +
            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 documentation for Rfm::Layout, Rfm::Record, and Rfm::Base.
         
     | 
| 
      
 312 
     | 
    
         
            +
             
     | 
| 
      
 313 
     | 
    
         
            +
             
     | 
| 
      
 314 
     | 
    
         
            +
            # Working with "classic" Rfm features
         
     | 
| 
      
 315 
     | 
    
         
            +
             
     | 
| 
      
 316 
     | 
    
         
            +
            All of Rfm's original features and functions are available as they were before, though some low-level functionality has changed slightly.
         
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
             
     | 
| 
       85 
319 
     | 
    
         
             
            ## Connecting
         
     | 
| 
       86 
320 
     | 
    
         | 
| 
       87 
321 
     | 
    
         
             
            IMPORTANT:SSL and Certificate verification are on by default. Please see Server#new in rdocs for explanation and setup.
         
     | 
| 
       88 
322 
     | 
    
         
             
            You connect with the Rfm::Server object. This little buddy will be your window into FileMaker data.
         
     | 
| 
       89 
323 
     | 
    
         | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
      
 324 
     | 
    
         
            +
            	   require 'rfm'
         
     | 
| 
       91 
325 
     | 
    
         | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
      
 326 
     | 
    
         
            +
            	   my_server = Rfm::Server.new(
         
     | 
| 
      
 327 
     | 
    
         
            +
            	     :host           => 'myservername',
         
     | 
| 
      
 328 
     | 
    
         
            +
            	     :account_name   => 'user',
         
     | 
| 
      
 329 
     | 
    
         
            +
            	     :password       => 'pw',
         
     | 
| 
      
 330 
     | 
    
         
            +
            	     :ssl            => false
         
     | 
| 
      
 331 
     | 
    
         
            +
            	   )
         
     | 
| 
       98 
332 
     | 
    
         | 
| 
       99 
333 
     | 
    
         
             
            if your web publishing engine runs on a port other than 80, you can provide the port number as well:
         
     | 
| 
       100 
334 
     | 
    
         | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
      
 335 
     | 
    
         
            +
            	   my_server = Rfm::Server.new(
         
     | 
| 
      
 336 
     | 
    
         
            +
            	     :host           => 'myservername',
         
     | 
| 
      
 337 
     | 
    
         
            +
            	     :account_name   => 'user',
         
     | 
| 
      
 338 
     | 
    
         
            +
            	     :password       => 'pw',
         
     | 
| 
      
 339 
     | 
    
         
            +
            	     :port           => 8080, 
         
     | 
| 
      
 340 
     | 
    
         
            +
            	     :ssl            => false,
         
     | 
| 
      
 341 
     | 
    
         
            +
            	     :root_cert      => false
         
     | 
| 
      
 342 
     | 
    
         
            +
            	   )
         
     | 
| 
       109 
343 
     | 
    
         | 
| 
       110 
344 
     | 
    
         
             
            ## Databases and Layouts
         
     | 
| 
       111 
345 
     | 
    
         | 
| 
       112 
346 
     | 
    
         
             
            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:
         
     | 
| 
       113 
347 
     | 
    
         | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
      
 348 
     | 
    
         
            +
            	   my_db = my_server.db["My Database"]
         
     | 
| 
       115 
349 
     | 
    
         | 
| 
       116 
350 
     | 
    
         
             
            As a convenience, you can do this too:
         
     | 
| 
       117 
351 
     | 
    
         | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
      
 352 
     | 
    
         
            +
            	   my_db = my_server["My Database"]
         
     | 
| 
       119 
353 
     | 
    
         | 
| 
       120 
354 
     | 
    
         
             
            Finally, if you want to introspect the server and find out what databases are available, you can do this:
         
     | 
| 
       121 
355 
     | 
    
         | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
      
 356 
     | 
    
         
            +
            	   all_dbs = my_server.db.all
         
     | 
| 
       123 
357 
     | 
    
         | 
| 
       124 
358 
     | 
    
         
             
            In any case, you get back Rfm::Database objects. A database object in turn has a property called "layout":
         
     | 
| 
       125 
359 
     | 
    
         | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
      
 360 
     | 
    
         
            +
            	   my_layout = my_db.layout["My Layout"]
         
     | 
| 
       127 
361 
     | 
    
         | 
| 
       128 
362 
     | 
    
         
             
            Again, for convenience:
         
     | 
| 
       129 
363 
     | 
    
         | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
      
 364 
     | 
    
         
            +
            	   my_layout = my_db["My Layout"]
         
     | 
| 
       131 
365 
     | 
    
         | 
| 
       132 
366 
     | 
    
         
             
            And to get them all:
         
     | 
| 
       133 
367 
     | 
    
         | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
      
 368 
     | 
    
         
            +
            	   all_layouts = my_db.layout.all
         
     | 
| 
       135 
369 
     | 
    
         | 
| 
       136 
370 
     | 
    
         
             
            Bringing it all together, you can do this to go straight from a server to a specific layout:
         
     | 
| 
       137 
371 
     | 
    
         | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
      
 372 
     | 
    
         
            +
            	   my_layout = my_server["My Database"]["My Layout"]
         
     | 
| 
       139 
373 
     | 
    
         | 
| 
       140 
374 
     | 
    
         
             
            ## Working with Layouts
         
     | 
| 
       141 
375 
     | 
    
         | 
| 
       142 
376 
     | 
    
         
             
            Once you have a layout object, you can start doing some real work. To get every record from the layout:
         
     | 
| 
       143 
377 
     | 
    
         | 
| 
       144 
     | 
    
         
            -
             
     | 
| 
      
 378 
     | 
    
         
            +
            	   my_layout.all   # be careful with this
         
     | 
| 
       145 
379 
     | 
    
         | 
| 
       146 
380 
     | 
    
         
             
            To get a random record:
         
     | 
| 
       147 
381 
     | 
    
         | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
                my_layout.any
         
     | 
| 
      
 382 
     | 
    
         
            +
            	   my_layout.any
         
     | 
| 
       150 
383 
     | 
    
         | 
| 
       151 
384 
     | 
    
         
             
            To find every record with "Arizona" in the "State" field:
         
     | 
| 
       152 
385 
     | 
    
         | 
| 
       153 
     | 
    
         
            -
             
     | 
| 
      
 386 
     | 
    
         
            +
            	   my_layout.find({"State" => "Arizona"})
         
     | 
| 
       154 
387 
     | 
    
         | 
| 
       155 
388 
     | 
    
         
             
            To add a new record with my personal info:
         
     | 
| 
       156 
389 
     | 
    
         | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
       158 
     | 
    
         
            -
             
     | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
       161 
     | 
    
         
            -
             
     | 
| 
      
 390 
     | 
    
         
            +
            	   my_layout.create({
         
     | 
| 
      
 391 
     | 
    
         
            +
            	     :first_name   => "Geoff",
         
     | 
| 
      
 392 
     | 
    
         
            +
            	     :last_name    => "Coffey",
         
     | 
| 
      
 393 
     | 
    
         
            +
            	     :email        => "gwcoffey@gmail.com"}
         
     | 
| 
      
 394 
     | 
    
         
            +
            	   )
         
     | 
| 
       162 
395 
     | 
    
         | 
| 
       163 
396 
     | 
    
         
             
            Notice that in this case I used symbols instead of strings for the hash keys. The API will accept either form, so if your field names don't have whitespace or punctuation, you might prefer the symbol notation.
         
     | 
| 
       164 
397 
     | 
    
         | 
| 
       165 
     | 
    
         
            -
            To edit the record  
     | 
| 
      
 398 
     | 
    
         
            +
            To edit the record whose recid (filemaker internal record id) is 200:
         
     | 
| 
       166 
399 
     | 
    
         | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
      
 400 
     | 
    
         
            +
            	   my_layout.edit(200, {:first_name => 'Mamie'})
         
     | 
| 
       168 
401 
     | 
    
         | 
| 
       169 
402 
     | 
    
         
             
            Note: See the "Record Objects" section below for more on editing records.
         
     | 
| 
       170 
403 
     | 
    
         | 
| 
       171 
404 
     | 
    
         
             
            To delete the record whose recid is 200:
         
     | 
| 
       172 
405 
     | 
    
         | 
| 
       173 
     | 
    
         
            -
             
     | 
| 
      
 406 
     | 
    
         
            +
            	   my_layout.delete(200)
         
     | 
| 
       174 
407 
     | 
    
         | 
| 
       175 
408 
     | 
    
         
             
            All of these methods return an Rfm::Result::ResultSet object (see below), and every one of them takes an optional parameter (the very last one) with additional options. For example, to find just a page full of records, you can do this:
         
     | 
| 
       176 
409 
     | 
    
         | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
      
 410 
     | 
    
         
            +
            	   my_layout.find({:state => "AZ"}, {:max_records => 10, :skip_records => 100})
         
     | 
| 
       178 
411 
     | 
    
         | 
| 
       179 
412 
     | 
    
         
             
            For a complete list of the available options, see the "expand_options" method in the Rfm::Server object in the file named rfm_command.rb.
         
     | 
| 
       180 
413 
     | 
    
         | 
| 
         @@ -185,84 +418,84 @@ Finally, if filemaker returns an error when executing any of these methods, an e 
     | 
|
| 
       185 
418 
     | 
    
         | 
| 
       186 
419 
     | 
    
         
             
            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:
         
     | 
| 
       187 
420 
     | 
    
         | 
| 
       188 
     | 
    
         
            -
             
     | 
| 
       189 
     | 
    
         
            -
             
     | 
| 
       190 
     | 
    
         
            -
             
     | 
| 
      
 421 
     | 
    
         
            +
            	   my_result = my_layout.any
         
     | 
| 
      
 422 
     | 
    
         
            +
            	   my_result.size  # returns '1'
         
     | 
| 
      
 423 
     | 
    
         
            +
            	   my_result[0]    # returns the first record (an Rfm::Result::Record object)
         
     | 
| 
       191 
424 
     | 
    
         | 
| 
       192 
425 
     | 
    
         
             
            The ResultSet object also tells you information about the fields and portals in the result. ResultSet#fields and ResultSet#portals are both standard ruby hashes, with strings for keys. The fields hash has Rfm::Result::Field objects for values. The portals hash has another hash for its values. This nested hash is the fields on the portal. This would print out all the field names:
         
     | 
| 
       193 
426 
     | 
    
         | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
      
 427 
     | 
    
         
            +
            	   my_result.fields.each { |name, field| puts name }
         
     | 
| 
       195 
428 
     | 
    
         | 
| 
       196 
429 
     | 
    
         
             
            This would print out the tables each portal on the layout is associated with. Below each table name, and indented, it will print the names of all the fields on each portal.
         
     | 
| 
       197 
430 
     | 
    
         | 
| 
       198 
     | 
    
         
            -
             
     | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
       201 
     | 
    
         
            -
             
     | 
| 
      
 431 
     | 
    
         
            +
            	   my_result.portals.each { |table, fields|
         
     | 
| 
      
 432 
     | 
    
         
            +
            	     puts "table: #{table}"
         
     | 
| 
      
 433 
     | 
    
         
            +
            	     fields.each { |name, field| puts "\t#{name}"}
         
     | 
| 
      
 434 
     | 
    
         
            +
            	   }
         
     | 
| 
       202 
435 
     | 
    
         | 
| 
       203 
436 
     | 
    
         
             
            But most importantly, the ResultSet contains record objects. Rfm::Result::Record is a subclass of Hash, so it can be used in many standard ways. This code would print the value in the 'first_name' field in the first record of the ResultSet:
         
     | 
| 
       204 
437 
     | 
    
         | 
| 
       205 
     | 
    
         
            -
             
     | 
| 
       206 
     | 
    
         
            -
             
     | 
| 
      
 438 
     | 
    
         
            +
            	   my_record = my_result[0]
         
     | 
| 
      
 439 
     | 
    
         
            +
            	   puts my_record["first_name"]
         
     | 
| 
       207 
440 
     | 
    
         | 
| 
       208 
441 
     | 
    
         
             
            As a convenience, if your field names are valid ruby method names (ie, they don't have spaces or odd punctuation in them), you can do this instead:
         
     | 
| 
       209 
442 
     | 
    
         | 
| 
       210 
     | 
    
         
            -
             
     | 
| 
      
 443 
     | 
    
         
            +
            	   puts my_record.first_name
         
     | 
| 
       211 
444 
     | 
    
         | 
| 
       212 
445 
     | 
    
         
             
            Since ResultSets are arrays and Records are hashes, you can take advantage of Ruby's wonderful expressiveness. For example, to get a comma-separated list of the full names of all the people in California, you could do this:
         
     | 
| 
       213 
446 
     | 
    
         | 
| 
       214 
     | 
    
         
            -
             
     | 
| 
      
 447 
     | 
    
         
            +
            	   my_layout.find(:state => 'CA').collect {|rec| "#{rec.first_name} #{rec.last_name}"}.join(", ")
         
     | 
| 
       215 
448 
     | 
    
         | 
| 
       216 
449 
     | 
    
         
             
            Record objects can also be edited:
         
     | 
| 
       217 
450 
     | 
    
         | 
| 
       218 
     | 
    
         
            -
             
     | 
| 
      
 451 
     | 
    
         
            +
            	   my_record.first_name = 'Isabel'
         
     | 
| 
       219 
452 
     | 
    
         | 
| 
       220 
453 
     | 
    
         
             
            Once you have made a series of edits, you can save them back to the database like this:
         
     | 
| 
       221 
454 
     | 
    
         | 
| 
       222 
     | 
    
         
            -
             
     | 
| 
      
 455 
     | 
    
         
            +
            	   my_record.save
         
     | 
| 
       223 
456 
     | 
    
         | 
| 
       224 
457 
     | 
    
         
             
            The save operation causes the record to be reloaded from the database, so any changes that have been made outside your script will also be picked up after the save.
         
     | 
| 
       225 
458 
     | 
    
         | 
| 
       226 
459 
     | 
    
         
             
            If you want to detect concurrent modification, you can do this instead:
         
     | 
| 
       227 
460 
     | 
    
         | 
| 
       228 
     | 
    
         
            -
             
     | 
| 
      
 461 
     | 
    
         
            +
            	   my_record.save_if_not_modified
         
     | 
| 
       229 
462 
     | 
    
         | 
| 
       230 
463 
     | 
    
         
             
            This version will refuse to update the database and raise an error if the record was modified after it was loaded but before it was saved.
         
     | 
| 
       231 
464 
     | 
    
         | 
| 
       232 
465 
     | 
    
         
             
            Record objects also have portals. While the portals in a ResultSet tell you about the tables and fields the portals show, the portals in a Record have the actual data. For example, if an Order record has Line Item records, you could do this:
         
     | 
| 
       233 
466 
     | 
    
         | 
| 
       234 
     | 
    
         
            -
             
     | 
| 
       235 
     | 
    
         
            -
             
     | 
| 
      
 467 
     | 
    
         
            +
            	   my_order = order_layout.any[0]  # the [0] is important!
         
     | 
| 
      
 468 
     | 
    
         
            +
            	   my_lines = my_order.portals["Line Items"]
         
     | 
| 
       236 
469 
     | 
    
         | 
| 
       237 
470 
     | 
    
         
             
            At the end of the previous block of code, my_lines is an array of Record objects. In this case, they are the records in the "Line Items" portal for the particular order record. You can then operate on them as you would any other record. 
         
     | 
| 
       238 
471 
     | 
    
         | 
| 
       239 
472 
     | 
    
         
             
            NOTE: Fields on a portal have the table name and the "::" stripped off of their names if they belong to the table the portal is tied to. In other words, if our "Line Items" portal includes a quantity field and a price field, you would do this:
         
     | 
| 
       240 
473 
     | 
    
         | 
| 
       241 
     | 
    
         
            -
             
     | 
| 
       242 
     | 
    
         
            -
             
     | 
| 
      
 474 
     | 
    
         
            +
            	   my_lines[0]["Quantity"]
         
     | 
| 
      
 475 
     | 
    
         
            +
            	   my_lines[0]["Price"]
         
     | 
| 
       243 
476 
     | 
    
         | 
| 
       244 
477 
     | 
    
         
             
            You would NOT do this:
         
     | 
| 
       245 
478 
     | 
    
         | 
| 
       246 
     | 
    
         
            -
             
     | 
| 
       247 
     | 
    
         
            -
             
     | 
| 
      
 479 
     | 
    
         
            +
            	   my_lines[0]["Line Items::Quantity"]
         
     | 
| 
      
 480 
     | 
    
         
            +
            	   my_lines[0]["Line Items::Quantity"]
         
     | 
| 
       248 
481 
     | 
    
         | 
| 
       249 
482 
     | 
    
         
             
            My feeling is that the table name is redundant and cumbersome if it is the same as the portal's table. This is also up for debate.
         
     | 
| 
       250 
483 
     | 
    
         | 
| 
       251 
484 
     | 
    
         
             
            Again, you can string things together with Ruby. This will calculate the total dollar amount of the order:
         
     | 
| 
       252 
485 
     | 
    
         | 
| 
       253 
     | 
    
         
            -
             
     | 
| 
       254 
     | 
    
         
            -
             
     | 
| 
      
 486 
     | 
    
         
            +
            	   total = 0.0
         
     | 
| 
      
 487 
     | 
    
         
            +
            	   my_order.portals["Line Items"].each {|line| total += line.quantity * line.price}
         
     | 
| 
       255 
488 
     | 
    
         | 
| 
       256 
489 
     | 
    
         
             
            ## Data Types
         
     | 
| 
       257 
490 
     | 
    
         | 
| 
       258 
491 
     | 
    
         
             
            FileMaker's field types are coerced to Ruby types thusly:
         
     | 
| 
       259 
492 
     | 
    
         | 
| 
       260 
     | 
    
         
            -
             
     | 
| 
       261 
     | 
    
         
            -
             
     | 
| 
       262 
     | 
    
         
            -
             
     | 
| 
       263 
     | 
    
         
            -
             
     | 
| 
       264 
     | 
    
         
            -
             
     | 
| 
       265 
     | 
    
         
            -
             
     | 
| 
      
 493 
     | 
    
         
            +
            	   Text Field       -> String object  
         
     | 
| 
      
 494 
     | 
    
         
            +
            	   Number Field     -> BigDecimal object  # see below  
         
     | 
| 
      
 495 
     | 
    
         
            +
            	   Date Field       -> Date object  
         
     | 
| 
      
 496 
     | 
    
         
            +
            	   Time Field       -> DateTime object # see below  
         
     | 
| 
      
 497 
     | 
    
         
            +
            	   TimeStamp Field  -> DateTime object  
         
     | 
| 
      
 498 
     | 
    
         
            +
            	   Container Field  -> URI object  
         
     | 
| 
       266 
499 
     | 
    
         | 
| 
       267 
500 
     | 
    
         
             
            FileMaker's number field is insanely robust. The only data type in ruby that can handle the same magnitude and precision of a FileMaker number is Ruby's BigDecimal. (This is an extension class, so you have to require 'bigdecimal' to use it yourself). Unfortuantely, BigDecimal is not a "normal" ruby numeric class, so it might be really annoying that your tiny filemaker numbers have to go this route. This is a great topic for debate.
         
     | 
| 
       268 
501 
     | 
    
         | 
| 
         @@ -270,9 +503,9 @@ Also, Ruby doesn't have a Time type that stores just a normal time (with no date 
     | 
|
| 
       270 
503 
     | 
    
         | 
| 
       271 
504 
     | 
    
         
             
            Finally, container fields will come back as URI objects. You can:
         
     | 
| 
       272 
505 
     | 
    
         | 
| 
       273 
     | 
    
         
            -
             
     | 
| 
       274 
     | 
    
         
            -
             
     | 
| 
       275 
     | 
    
         
            -
             
     | 
| 
      
 506 
     | 
    
         
            +
            	- use Net::HTTP to download the contents of the container field using this URI
         
     | 
| 
      
 507 
     | 
    
         
            +
            	- to_s the URI and use it as the src attribute of an HTML image tag
         
     | 
| 
      
 508 
     | 
    
         
            +
            	- etc...
         
     | 
| 
       276 
509 
     | 
    
         | 
| 
       277 
510 
     | 
    
         
             
            Specifically, the URI refers to the _contents_ of the container field. When accessed, the file, picture, or movie in the field will be downloaded.
         
     | 
| 
       278 
511 
     | 
    
         | 
| 
         @@ -288,13 +521,25 @@ When this is 'true' your script will dump the actual response it got from FileMa 
     | 
|
| 
       288 
521 
     | 
    
         | 
| 
       289 
522 
     | 
    
         
             
            So, for an annoying, but detailed load of output, make a connection like this:
         
     | 
| 
       290 
523 
     | 
    
         | 
| 
       291 
     | 
    
         
            -
             
     | 
| 
       292 
     | 
    
         
            -
             
     | 
| 
       293 
     | 
    
         
            -
             
     | 
| 
       294 
     | 
    
         
            -
             
     | 
| 
       295 
     | 
    
         
            -
             
     | 
| 
       296 
     | 
    
         
            -
             
     | 
| 
       297 
     | 
    
         
            -
             
     | 
| 
      
 524 
     | 
    
         
            +
            	   my_server => Rfm::Server.new(
         
     | 
| 
      
 525 
     | 
    
         
            +
            	     :host             => 'myservername',
         
     | 
| 
      
 526 
     | 
    
         
            +
            	     :account_name     => 'user',
         
     | 
| 
      
 527 
     | 
    
         
            +
            	     :password         => 'pw',
         
     | 
| 
      
 528 
     | 
    
         
            +
            	     :log_actions      => true,
         
     | 
| 
      
 529 
     | 
    
         
            +
            	     :log_responses    => true
         
     | 
| 
      
 530 
     | 
    
         
            +
            	   )
         
     | 
| 
      
 531 
     | 
    
         
            +
             
     | 
| 
      
 532 
     | 
    
         
            +
             
     | 
| 
      
 533 
     | 
    
         
            +
            ## Credits
         
     | 
| 
      
 534 
     | 
    
         
            +
             
     | 
| 
      
 535 
     | 
    
         
            +
            Rfm was primarily designed by Six Fried Rice co-founder Geoff Coffey.
         
     | 
| 
      
 536 
     | 
    
         
            +
             
     | 
| 
      
 537 
     | 
    
         
            +
            Other lead contributors:
         
     | 
| 
      
 538 
     | 
    
         
            +
             
     | 
| 
      
 539 
     | 
    
         
            +
            * Mufaddal Khumri helped architect Rfm in the most ruby-like way possible. He also contributed the outstanding error handling code and a comprehensive hierarchy of error classes.
         
     | 
| 
      
 540 
     | 
    
         
            +
            * Atsushi Matsuo was an early Rfm tester, and provided outstanding feedback, critical code fixes, and a lot of web exposure.
         
     | 
| 
      
 541 
     | 
    
         
            +
            * Jesse Antunes helped ensure that Rfm is stable and functional.
         
     | 
| 
      
 542 
     | 
    
         
            +
            * Larry Sprock added ssl support, switched the xml parser to a much faster Nokogiri, added the rspec testing framework, and refined code architecture.
         
     | 
| 
       298 
543 
     | 
    
         | 
| 
       299 
544 
     | 
    
         
             
            ## Copyright
         
     | 
| 
       300 
545 
     | 
    
         |