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/lib/rfm.rb
    CHANGED
    
    | 
         @@ -3,34 +3,66 @@ module Rfm 
     | 
|
| 
       3 
3 
     | 
    
         
             
            	$LOAD_PATH.unshift(PATH) unless $LOAD_PATH.include?(PATH)
         
     | 
| 
       4 
4 
     | 
    
         
             
            end
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
      
 6 
     | 
    
         
            +
            require 'thread' # some versions of ActiveSupport will raise error about Mutex unless 'thread' is loaded.
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'active_support'
         
     | 
| 
      
 8 
     | 
    
         
            +
            # ActiveSupport appears to load these automatcially
         
     | 
| 
      
 9 
     | 
    
         
            +
            	#require 'active_support/core_ext/object/blank'
         
     | 
| 
      
 10 
     | 
    
         
            +
            	#require 'active_support/ordered_hash'
         
     | 
| 
      
 11 
     | 
    
         
            +
            	require 'active_support/version'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'rfm/utilities/core_ext'
         
     | 
| 
       6 
13 
     | 
    
         
             
            require 'rfm/utilities/case_insensitive_hash'
         
     | 
| 
       7 
     | 
    
         
            -
            require 'rfm/utilities/ 
     | 
| 
       8 
     | 
    
         
            -
            require 'rfm/ 
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 14 
     | 
    
         
            +
            #require 'rfm/utilities/config'
         
     | 
| 
      
 15 
     | 
    
         
            +
            #require 'rfm/utilities/factory'
         
     | 
| 
      
 16 
     | 
    
         
            +
            #require 'rfm/version.rb'
         
     | 
| 
       10 
17 
     | 
    
         | 
| 
       11 
18 
     | 
    
         
             
            module Rfm
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            	if $0.to_s.match(/irb|rails|bundle/) # was ENV['_']
         
     | 
| 
       14 
     | 
    
         
            -
              	puts "Using gem ginjo-rfm version: #{::Rfm::VERSION}"
         
     | 
| 
       15 
     | 
    
         
            -
              end
         
     | 
| 
       16 
19 
     | 
    
         | 
| 
       17 
20 
     | 
    
         
             
              class CommunicationError  < StandardError; end
         
     | 
| 
       18 
21 
     | 
    
         
             
              class ParameterError      < StandardError; end
         
     | 
| 
       19 
22 
     | 
    
         
             
              class AuthenticationError < StandardError; end
         
     | 
| 
       20 
23 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
              autoload :Error, 
     | 
| 
       22 
     | 
    
         
            -
              autoload :Server, 
     | 
| 
       23 
     | 
    
         
            -
              autoload :Database, 
     | 
| 
       24 
     | 
    
         
            -
              autoload :Layout, 
     | 
| 
       25 
     | 
    
         
            -
              autoload :Resultset, 
     | 
| 
       26 
     | 
    
         
            -
              autoload :Record, 
     | 
| 
      
 24 
     | 
    
         
            +
              autoload :Error,        'rfm/error'
         
     | 
| 
      
 25 
     | 
    
         
            +
              autoload :Server,       'rfm/server'
         
     | 
| 
      
 26 
     | 
    
         
            +
              autoload :Database,     'rfm/database'
         
     | 
| 
      
 27 
     | 
    
         
            +
              autoload :Layout,       'rfm/layout'
         
     | 
| 
      
 28 
     | 
    
         
            +
              autoload :Resultset,    'rfm/resultset'
         
     | 
| 
      
 29 
     | 
    
         
            +
              autoload :Record,       'rfm/record'
         
     | 
| 
      
 30 
     | 
    
         
            +
              autoload :Base,         'rfm/base'
         
     | 
| 
      
 31 
     | 
    
         
            +
              autoload :XmlParser,    'rfm/utilities/xml_parser'
         
     | 
| 
      
 32 
     | 
    
         
            +
              autoload :ComplexQuery, 'rfm/utilities/complex_query'
         
     | 
| 
      
 33 
     | 
    
         
            +
              autoload :Config,       'rfm/utilities/config'
         
     | 
| 
      
 34 
     | 
    
         
            +
              autoload :Factory,      'rfm/utilities/factory'
         
     | 
| 
      
 35 
     | 
    
         
            +
              autoload :VERSION,      'rfm/version'
         
     | 
| 
       27 
36 
     | 
    
         | 
| 
       28 
37 
     | 
    
         
             
            	module Metadata
         
     | 
| 
       29 
     | 
    
         
            -
            		autoload :Script, 
     | 
| 
       30 
     | 
    
         
            -
            		autoload :Field, 
     | 
| 
       31 
     | 
    
         
            -
            		autoload :FieldControl, 
     | 
| 
       32 
     | 
    
         
            -
            		autoload :ValueListItem, 
     | 
| 
      
 38 
     | 
    
         
            +
            		autoload :Script,         'rfm/metadata/script'
         
     | 
| 
      
 39 
     | 
    
         
            +
            		autoload :Field,          'rfm/metadata/field'
         
     | 
| 
      
 40 
     | 
    
         
            +
            		autoload :FieldControl,   'rfm/metadata/field_control'
         
     | 
| 
      
 41 
     | 
    
         
            +
            		autoload :ValueListItem,  'rfm/metadata/value_list_item'
         
     | 
| 
       33 
42 
     | 
    
         
             
            	end
         
     | 
| 
       34 
     | 
    
         
            -
            	  
         
     | 
| 
       35 
     | 
    
         
            -
            end
         
     | 
| 
       36 
43 
     | 
    
         | 
| 
      
 44 
     | 
    
         
            +
            	def info
         
     | 
| 
      
 45 
     | 
    
         
            +
                rslt = <<-EEOOFF
         
     | 
| 
      
 46 
     | 
    
         
            +
                  Name: ginjo-rfm
         
     | 
| 
      
 47 
     | 
    
         
            +
                  Version: #{VERSION}
         
     | 
| 
      
 48 
     | 
    
         
            +
                  ActiveSupport Version: #{ActiveSupport::VERSION::STRING}
         
     | 
| 
      
 49 
     | 
    
         
            +
                  ActiveModel Loaded? #{defined?(ActiveModel) ? 'true' : 'false'}
         
     | 
| 
      
 50 
     | 
    
         
            +
                  ActiveModel Loadable? #{begin; require 'active_model'; rescue LoadError; $!; end}
         
     | 
| 
      
 51 
     | 
    
         
            +
                  XML Parser: #{XmlParser.backend}
         
     | 
| 
      
 52 
     | 
    
         
            +
                EEOOFF
         
     | 
| 
      
 53 
     | 
    
         
            +
                rslt.gsub!(/^[ \t]*/, '')
         
     | 
| 
      
 54 
     | 
    
         
            +
              rescue
         
     | 
| 
      
 55 
     | 
    
         
            +
              	"Could not retrieve info: #{$!}"
         
     | 
| 
      
 56 
     | 
    
         
            +
            	end
         
     | 
| 
      
 57 
     | 
    
         
            +
            	
         
     | 
| 
      
 58 
     | 
    
         
            +
            	def info_short
         
     | 
| 
      
 59 
     | 
    
         
            +
            		"Using ginjo-rfm version #{::Rfm::VERSION} with #{XmlParser.backend}"
         
     | 
| 
      
 60 
     | 
    
         
            +
            	end
         
     | 
| 
      
 61 
     | 
    
         
            +
            	
         
     | 
| 
      
 62 
     | 
    
         
            +
            	def_delegators 'Rfm::Factory', :servers, :server, :db, :database, :layout, :models, :modelize
         
     | 
| 
      
 63 
     | 
    
         
            +
            	def_delegators 'Rfm::XmlParser', :backend, :backend=
         
     | 
| 
      
 64 
     | 
    
         
            +
            	def_delegators 'Rfm::Config', :config, :get_config, :config_clear
         
     | 
| 
      
 65 
     | 
    
         
            +
            	
         
     | 
| 
      
 66 
     | 
    
         
            +
            	extend self
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            end # Rfm
         
     | 
    
        data/lib/rfm/VERSION
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            2.0.pre31
         
     | 
    
        data/lib/rfm/base.rb
    ADDED
    
    | 
         @@ -0,0 +1,416 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Rfm
         
     | 
| 
      
 2 
     | 
    
         
            +
            	#
         
     | 
| 
      
 3 
     | 
    
         
            +
            	# Adds ability to create Rfm::Base model classes that behave similar to ActiveRecord::Base models.
         
     | 
| 
      
 4 
     | 
    
         
            +
            	# If you set your Rfm.config (or RFM_CONFIG) with your host, database, account, password, and
         
     | 
| 
      
 5 
     | 
    
         
            +
            	# any other server/database options, you can provide your models with nothing more than a layout.
         
     | 
| 
      
 6 
     | 
    
         
            +
            	#
         
     | 
| 
      
 7 
     | 
    
         
            +
            	# 	class Person < Rfm::Base
         
     | 
| 
      
 8 
     | 
    
         
            +
            	# 	  config :layout => 'mylayout'
         
     | 
| 
      
 9 
     | 
    
         
            +
            	# 	end
         
     | 
| 
      
 10 
     | 
    
         
            +
            	#
         
     | 
| 
      
 11 
     | 
    
         
            +
            	# And similar to ActiveRecord, you can define callbacks, validations, attributes, and methods on your model.
         
     | 
| 
      
 12 
     | 
    
         
            +
            	#
         
     | 
| 
      
 13 
     | 
    
         
            +
            	#   class Account < Rfm::Base
         
     | 
| 
      
 14 
     | 
    
         
            +
            	#     config :layout=>'account_xml'
         
     | 
| 
      
 15 
     | 
    
         
            +
            	#     before_create :encrypt_password
         
     | 
| 
      
 16 
     | 
    
         
            +
            	#     validates :email, :presence => true
         
     | 
| 
      
 17 
     | 
    
         
            +
            	#     validates :username, :presence => true
         
     | 
| 
      
 18 
     | 
    
         
            +
            	#     attr_accessor :password
         
     | 
| 
      
 19 
     | 
    
         
            +
            	#   end
         
     | 
| 
      
 20 
     | 
    
         
            +
            	#   
         
     | 
| 
      
 21 
     | 
    
         
            +
            	# Then in your project, you can use these models just like ActiveRecord models.
         
     | 
| 
      
 22 
     | 
    
         
            +
            	# The query syntax and options are still Rfm under the hood. Treat your model
         
     | 
| 
      
 23 
     | 
    
         
            +
            	# classes like Rfm::Layout objects, with a few enhancements.
         
     | 
| 
      
 24 
     | 
    
         
            +
            	#
         
     | 
| 
      
 25 
     | 
    
         
            +
            	#   @account = Account.new :username => 'bill', :password => 'pass'
         
     | 
| 
      
 26 
     | 
    
         
            +
            	#   @account.email = 'my@email.com'
         
     | 
| 
      
 27 
     | 
    
         
            +
            	#   @account.save!
         
     | 
| 
      
 28 
     | 
    
         
            +
            	#   
         
     | 
| 
      
 29 
     | 
    
         
            +
            	#   @person = Person.find({:name => 'mike'}, :max_records => 50)[0]
         
     | 
| 
      
 30 
     | 
    
         
            +
            	#   @person.update_attributes(:name => 'Michael', :title => "Senior Partner")
         
     | 
| 
      
 31 
     | 
    
         
            +
            	#   @person.save
         
     | 
| 
      
 32 
     | 
    
         
            +
            	# 
         
     | 
| 
      
 33 
     | 
    
         
            +
            	# 
         
     | 
| 
      
 34 
     | 
    
         
            +
            	#
         
     | 
| 
      
 35 
     | 
    
         
            +
            	#
         
     | 
| 
      
 36 
     | 
    
         
            +
            	# :nodoc: TODO: make sure all methods return something (a record?) if successful, otherwise nil or error
         
     | 
| 
      
 37 
     | 
    
         
            +
            	# :nodoc: TODO: move rfm methods & patches from fetch_mail_with_ruby to this file
         
     | 
| 
      
 38 
     | 
    
         
            +
            	#
         
     | 
| 
      
 39 
     | 
    
         
            +
            	# TODO: Are these really needed here?
         
     | 
| 
      
 40 
     | 
    
         
            +
            	require 'rfm/database'
         
     | 
| 
      
 41 
     | 
    
         
            +
            	require 'rfm/layout'
         
     | 
| 
      
 42 
     | 
    
         
            +
            	require 'rfm/record'
         
     | 
| 
      
 43 
     | 
    
         
            +
            	require 'rfm/utilities/factory'
         
     | 
| 
      
 44 
     | 
    
         
            +
            	require 'delegate'
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              
         
     | 
| 
      
 47 
     | 
    
         
            +
              
         
     | 
| 
      
 48 
     | 
    
         
            +
              class Layout
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              	class SubLayout < DelegateClass(Layout)
         
     | 
| 
      
 51 
     | 
    
         
            +
              		include Layout::LayoutModule
         
     | 
| 
      
 52 
     | 
    
         
            +
               		attr_accessor :model, :parent_layout
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              		def initialize(master)
         
     | 
| 
      
 55 
     | 
    
         
            +
              			super(master)
         
     | 
| 
      
 56 
     | 
    
         
            +
              			self.parent_layout = master
         
     | 
| 
      
 57 
     | 
    
         
            +
              		end
         
     | 
| 
      
 58 
     | 
    
         
            +
              	end # SubLayout
         
     | 
| 
      
 59 
     | 
    
         
            +
              	
         
     | 
| 
      
 60 
     | 
    
         
            +
                attr_accessor :subs
         
     | 
| 
      
 61 
     | 
    
         
            +
              	
         
     | 
| 
      
 62 
     | 
    
         
            +
              	alias_method :main_init, :initialize
         
     | 
| 
      
 63 
     | 
    
         
            +
            		def initialize(*args)
         
     | 
| 
      
 64 
     | 
    
         
            +
            	    @subs ||= []
         
     | 
| 
      
 65 
     | 
    
         
            +
            	    main_init(*args)
         
     | 
| 
      
 66 
     | 
    
         
            +
            	  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                
         
     | 
| 
      
 68 
     | 
    
         
            +
                def sublayout
         
     | 
| 
      
 69 
     | 
    
         
            +
                	if self.is_a?(Rfm::Layout)
         
     | 
| 
      
 70 
     | 
    
         
            +
                		sub = SubLayout.new(self); subs << sub; sub
         
     | 
| 
      
 71 
     | 
    
         
            +
                	else
         
     | 
| 
      
 72 
     | 
    
         
            +
                		self
         
     | 
| 
      
 73 
     | 
    
         
            +
                	end
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
              	
         
     | 
| 
      
 76 
     | 
    
         
            +
                # Creates new class with layout name, subclassed from Rfm::Base, and links the new model to a SubLayout instance.
         
     | 
| 
      
 77 
     | 
    
         
            +
                def modelize
         
     | 
| 
      
 78 
     | 
    
         
            +
                	model_name = name.to_s.gsub(/\W/, '_').classify.gsub(/_/,'')
         
     | 
| 
      
 79 
     | 
    
         
            +
                	(return model_name.constantize) rescue nil
         
     | 
| 
      
 80 
     | 
    
         
            +
                	sub = sublayout
         
     | 
| 
      
 81 
     | 
    
         
            +
                	sub.instance_eval do
         
     | 
| 
      
 82 
     | 
    
         
            +
            	    	model_class = eval("::" + model_name + "= Class.new(Rfm::Base)")
         
     | 
| 
      
 83 
     | 
    
         
            +
            	    	model_class.class_exec(self) do |layout_obj|
         
     | 
| 
      
 84 
     | 
    
         
            +
            	    		@layout = layout_obj
         
     | 
| 
      
 85 
     | 
    
         
            +
            	    	end
         
     | 
| 
      
 86 
     | 
    
         
            +
            	    	@model = model_class
         
     | 
| 
      
 87 
     | 
    
         
            +
            	    end
         
     | 
| 
      
 88 
     | 
    
         
            +
            	    sub.model.to_s.constantize
         
     | 
| 
      
 89 
     | 
    
         
            +
                rescue StandardError, SyntaxError
         
     | 
| 
      
 90 
     | 
    
         
            +
                	nil
         
     | 
| 
      
 91 
     | 
    
         
            +
              	end
         
     | 
| 
      
 92 
     | 
    
         
            +
              	
         
     | 
| 
      
 93 
     | 
    
         
            +
              	def models
         
     | 
| 
      
 94 
     | 
    
         
            +
              		subs.collect{|s| s.model}
         
     | 
| 
      
 95 
     | 
    
         
            +
              	end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
              end # Layout
         
     | 
| 
      
 98 
     | 
    
         
            +
              
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    
         
     | 
| 
      
 103 
     | 
    
         
            +
              class Record
         
     | 
| 
      
 104 
     | 
    
         
            +
              	class << self
         
     | 
| 
      
 105 
     | 
    
         
            +
            			def new(*args)
         
     | 
| 
      
 106 
     | 
    
         
            +
            				#puts "Creating new record from RECORD. Layout: #{args[3].class} #{args[3].object_id}"
         
     | 
| 
      
 107 
     | 
    
         
            +
            				args[3].model.new(*args)
         
     | 
| 
      
 108 
     | 
    
         
            +
            			rescue
         
     | 
| 
      
 109 
     | 
    
         
            +
            				#puts "RECORD failed to send 'new' to MODEL"
         
     | 
| 
      
 110 
     | 
    
         
            +
            				super
         
     | 
| 
      
 111 
     | 
    
         
            +
            				#allocate.send(:initialize, *args)
         
     | 
| 
      
 112 
     | 
    
         
            +
            			end
         
     | 
| 
      
 113 
     | 
    
         
            +
                end # class << self
         
     | 
| 
      
 114 
     | 
    
         
            +
              end # class Record
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
              
         
     | 
| 
      
 120 
     | 
    
         
            +
              class Database
         
     | 
| 
      
 121 
     | 
    
         
            +
              	def_delegators :layouts, :modelize, :models
         
     | 
| 
      
 122 
     | 
    
         
            +
              end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
              
         
     | 
| 
      
 127 
     | 
    
         
            +
              module Factory
         
     | 
| 
      
 128 
     | 
    
         
            +
                @models ||= []
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
              	class << self
         
     | 
| 
      
 131 
     | 
    
         
            +
              		attr_accessor :models
         
     | 
| 
      
 132 
     | 
    
         
            +
              		
         
     | 
| 
      
 133 
     | 
    
         
            +
            	  	# Shortcut to Factory.db().layouts.modelize()
         
     | 
| 
      
 134 
     | 
    
         
            +
            	  	# If first parameter is regex, it is used for modelize filter.
         
     | 
| 
      
 135 
     | 
    
         
            +
            	  	# Otherwise, parameters are passed to Factory.database
         
     | 
| 
      
 136 
     | 
    
         
            +
            	  	def modelize(*args)
         
     | 
| 
      
 137 
     | 
    
         
            +
            	  		regx = args[0].is_a?(Regexp) ? args.shift : /.*/
         
     | 
| 
      
 138 
     | 
    
         
            +
            	  		db(*args).layouts.modelize(regx)
         
     | 
| 
      
 139 
     | 
    
         
            +
            	  	end
         
     | 
| 
      
 140 
     | 
    
         
            +
              	end # class << self
         
     | 
| 
      
 141 
     | 
    
         
            +
              	
         
     | 
| 
      
 142 
     | 
    
         
            +
              	class LayoutFactory
         
     | 
| 
      
 143 
     | 
    
         
            +
                	def modelize(filter = /.*/)
         
     | 
| 
      
 144 
     | 
    
         
            +
                		all.values.each{|lay| lay.modelize if lay.name.match(filter)}
         
     | 
| 
      
 145 
     | 
    
         
            +
                		models
         
     | 
| 
      
 146 
     | 
    
         
            +
                	end
         
     | 
| 
      
 147 
     | 
    
         
            +
                	
         
     | 
| 
      
 148 
     | 
    
         
            +
                	def models
         
     | 
| 
      
 149 
     | 
    
         
            +
            	    	rslt = {}
         
     | 
| 
      
 150 
     | 
    
         
            +
                		each do |k,lay|
         
     | 
| 
      
 151 
     | 
    
         
            +
                			layout_models = lay.models
         
     | 
| 
      
 152 
     | 
    
         
            +
                			rslt[k] = layout_models if !layout_models.blank?
         
     | 
| 
      
 153 
     | 
    
         
            +
            	    	end
         
     | 
| 
      
 154 
     | 
    
         
            +
            	    	rslt
         
     | 
| 
      
 155 
     | 
    
         
            +
                	end
         
     | 
| 
      
 156 
     | 
    
         
            +
                	
         
     | 
| 
      
 157 
     | 
    
         
            +
                end # LayoutFactory
         
     | 
| 
      
 158 
     | 
    
         
            +
              end # Factory
         
     | 
| 
      
 159 
     | 
    
         
            +
            	
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
            	
         
     | 
| 
      
 163 
     | 
    
         
            +
              class Base <  Rfm::Record  #Hash
         
     | 
| 
      
 164 
     | 
    
         
            +
                extend Config
         
     | 
| 
      
 165 
     | 
    
         
            +
                config :parent => 'Rfm::Config'
         
     | 
| 
      
 166 
     | 
    
         
            +
                
         
     | 
| 
      
 167 
     | 
    
         
            +
                begin
         
     | 
| 
      
 168 
     | 
    
         
            +
                	require 'active_model'
         
     | 
| 
      
 169 
     | 
    
         
            +
                  include ActiveModel::Validations
         
     | 
| 
      
 170 
     | 
    
         
            +
                  include ActiveModel::Serialization
         
     | 
| 
      
 171 
     | 
    
         
            +
                  extend ActiveModel::Callbacks
         
     | 
| 
      
 172 
     | 
    
         
            +
                  define_model_callbacks(:create, :update, :destroy)
         
     | 
| 
      
 173 
     | 
    
         
            +
                rescue LoadError, StandardError
         
     | 
| 
      
 174 
     | 
    
         
            +
                	def run_callbacks(*args)
         
     | 
| 
      
 175 
     | 
    
         
            +
                		yield
         
     | 
| 
      
 176 
     | 
    
         
            +
                	end
         
     | 
| 
      
 177 
     | 
    
         
            +
                end
         
     | 
| 
      
 178 
     | 
    
         
            +
                
         
     | 
| 
      
 179 
     | 
    
         
            +
            		def initialize(record={}, resultset_obj=[], field_meta='', layout_obj=self.class.layout, portal=nil)
         
     | 
| 
      
 180 
     | 
    
         
            +
            			if resultset_obj == [] and !record.has_key? 'field'
         
     | 
| 
      
 181 
     | 
    
         
            +
            				@mods = Rfm::CaseInsensitiveHash.new
         
     | 
| 
      
 182 
     | 
    
         
            +
            				@layout = layout_obj
         
     | 
| 
      
 183 
     | 
    
         
            +
            				@resultset = Resultset.allocate
         
     | 
| 
      
 184 
     | 
    
         
            +
                    # loop thru each layout field, creating hash keys with nil values
         
     | 
| 
      
 185 
     | 
    
         
            +
                    layout_obj.field_names.each do |field|
         
     | 
| 
      
 186 
     | 
    
         
            +
                      field_name = field.to_s
         
     | 
| 
      
 187 
     | 
    
         
            +
                      self[field_name] = nil
         
     | 
| 
      
 188 
     | 
    
         
            +
                    end
         
     | 
| 
      
 189 
     | 
    
         
            +
                    self.update_attributes(record) unless record == {}
         
     | 
| 
      
 190 
     | 
    
         
            +
                    self.merge!(@mods) unless @mods == {}
         
     | 
| 
      
 191 
     | 
    
         
            +
                    @loaded = true
         
     | 
| 
      
 192 
     | 
    
         
            +
                  else
         
     | 
| 
      
 193 
     | 
    
         
            +
                  	super
         
     | 
| 
      
 194 
     | 
    
         
            +
                  end
         
     | 
| 
      
 195 
     | 
    
         
            +
            		end
         
     | 
| 
      
 196 
     | 
    
         
            +
            		
         
     | 
| 
      
 197 
     | 
    
         
            +
            		
         
     | 
| 
      
 198 
     | 
    
         
            +
            		class << self
         
     | 
| 
      
 199 
     | 
    
         
            +
            		
         
     | 
| 
      
 200 
     | 
    
         
            +
            	    # Access layout functions from base model
         
     | 
| 
      
 201 
     | 
    
         
            +
            	  	def_delegators :layout, :db, :server, :field_controls, :field_names, :value_lists, :total_count,
         
     | 
| 
      
 202 
     | 
    
         
            +
            	  									:query, :all, :delete, :portal_meta, :portal_names, :database, :table
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
            			def inherited(model)
         
     | 
| 
      
 205 
     | 
    
         
            +
            				(Rfm::Factory.models << model).uniq unless Rfm::Factory.models.include? model
         
     | 
| 
      
 206 
     | 
    
         
            +
            				model.config :parent=>'Rfm::Base'
         
     | 
| 
      
 207 
     | 
    
         
            +
            			end
         
     | 
| 
      
 208 
     | 
    
         
            +
            		
         
     | 
| 
      
 209 
     | 
    
         
            +
            			# Build a new record without saving
         
     | 
| 
      
 210 
     | 
    
         
            +
            		  def new(*args)
         
     | 
| 
      
 211 
     | 
    
         
            +
            		  	# Without this method, infinite recursion will happen from Record.new
         
     | 
| 
      
 212 
     | 
    
         
            +
            		  	#puts "Creating new record from BASE"
         
     | 
| 
      
 213 
     | 
    
         
            +
            		    rec = self.allocate
         
     | 
| 
      
 214 
     | 
    
         
            +
            		    rec.send(:initialize, *args)
         
     | 
| 
      
 215 
     | 
    
         
            +
            		    rec
         
     | 
| 
      
 216 
     | 
    
         
            +
            		  end
         
     | 
| 
      
 217 
     | 
    
         
            +
            		  
         
     | 
| 
      
 218 
     | 
    
         
            +
            	    def config(*args)
         
     | 
| 
      
 219 
     | 
    
         
            +
            	    	super(*args){|strings| @config.merge!(:layout=>strings[0]) if strings[0]}
         
     | 
| 
      
 220 
     | 
    
         
            +
            	    end
         
     | 
| 
      
 221 
     | 
    
         
            +
            		  		  			
         
     | 
| 
      
 222 
     | 
    
         
            +
            			# Access/create the layout object associated with this model
         
     | 
| 
      
 223 
     | 
    
         
            +
            	  	def layout
         
     | 
| 
      
 224 
     | 
    
         
            +
            	  		return @layout if @layout
         
     | 
| 
      
 225 
     | 
    
         
            +
            	  		cnf = get_config
         
     | 
| 
      
 226 
     | 
    
         
            +
            	  		return unless cnf[:layout]
         
     | 
| 
      
 227 
     | 
    
         
            +
            	  		@layout = Rfm::Factory.layout(get_config).sublayout
         
     | 
| 
      
 228 
     | 
    
         
            +
            				@layout.model = self
         
     | 
| 
      
 229 
     | 
    
         
            +
            				@layout
         
     | 
| 
      
 230 
     | 
    
         
            +
            	  	end
         
     | 
| 
      
 231 
     | 
    
         
            +
            		  			
         
     | 
| 
      
 232 
     | 
    
         
            +
            			# Just like Layout#find, but searching by record_id will return a record, not a resultset.
         
     | 
| 
      
 233 
     | 
    
         
            +
            	  	def find(*args)
         
     | 
| 
      
 234 
     | 
    
         
            +
            	  	  r = layout.find(*args)
         
     | 
| 
      
 235 
     | 
    
         
            +
            	  	  if args[0].class != Hash and r.size == 1
         
     | 
| 
      
 236 
     | 
    
         
            +
            	  	    r[0]
         
     | 
| 
      
 237 
     | 
    
         
            +
            		    else
         
     | 
| 
      
 238 
     | 
    
         
            +
            		      r
         
     | 
| 
      
 239 
     | 
    
         
            +
            	      end
         
     | 
| 
      
 240 
     | 
    
         
            +
            	    rescue Rfm::Error::RecordMissingError
         
     | 
| 
      
 241 
     | 
    
         
            +
            	      nil
         
     | 
| 
      
 242 
     | 
    
         
            +
            	  	end
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
            			# Layout#any, returns single record, not resultset
         
     | 
| 
      
 245 
     | 
    
         
            +
            	  	def any(*args)
         
     | 
| 
      
 246 
     | 
    
         
            +
            	  	  layout.any(*args)[0]
         
     | 
| 
      
 247 
     | 
    
         
            +
            	  	end
         
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
      
 249 
     | 
    
         
            +
            			# New record, save, (with callbacks & validations if ActiveModel is loaded)
         
     | 
| 
      
 250 
     | 
    
         
            +
            	  	def create(*args)
         
     | 
| 
      
 251 
     | 
    
         
            +
            	  	  new(*args).send :create
         
     | 
| 
      
 252 
     | 
    
         
            +
            	  	end
         
     | 
| 
      
 253 
     | 
    
         
            +
            	  		  
         
     | 
| 
      
 254 
     | 
    
         
            +
            	    # Using this method will skip callbacks. Use instance method +#update+ instead
         
     | 
| 
      
 255 
     | 
    
         
            +
            		  def edit(*args)
         
     | 
| 
      
 256 
     | 
    
         
            +
            		    layout.edit(*args)[0]
         
     | 
| 
      
 257 
     | 
    
         
            +
            	    end
         
     | 
| 
      
 258 
     | 
    
         
            +
            	    
         
     | 
| 
      
 259 
     | 
    
         
            +
            		end # class << self
         
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
            		
         
     | 
| 
      
 263 
     | 
    
         
            +
            		
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
            		
         
     | 
| 
      
 266 
     | 
    
         
            +
            		# Is this a newly created record, not saved yet?					
         
     | 
| 
      
 267 
     | 
    
         
            +
              	def new_record?
         
     | 
| 
      
 268 
     | 
    
         
            +
              		return true if self.record_id.blank?
         
     | 
| 
      
 269 
     | 
    
         
            +
              	end
         
     | 
| 
      
 270 
     | 
    
         
            +
             
     | 
| 
      
 271 
     | 
    
         
            +
            		# Reload record from database
         
     | 
| 
      
 272 
     | 
    
         
            +
            		# TODO: handle error when record has been deleted
         
     | 
| 
      
 273 
     | 
    
         
            +
            		def reload(force=false)
         
     | 
| 
      
 274 
     | 
    
         
            +
            	    if (@mods.empty? or force) and record_id
         
     | 
| 
      
 275 
     | 
    
         
            +
            	      self.replace self.class.find(self.record_id)
         
     | 
| 
      
 276 
     | 
    
         
            +
                  end
         
     | 
| 
      
 277 
     | 
    
         
            +
                end
         
     | 
| 
      
 278 
     | 
    
         
            +
                
         
     | 
| 
      
 279 
     | 
    
         
            +
                # Mass update of record attributes, without saving.
         
     | 
| 
      
 280 
     | 
    
         
            +
                # TODO: return error or nil if input hash contains no recognizable keys.
         
     | 
| 
      
 281 
     | 
    
         
            +
                def update_attributes(new_attr)
         
     | 
| 
      
 282 
     | 
    
         
            +
                  # creates new special hash
         
     | 
| 
      
 283 
     | 
    
         
            +
                  input_hash = Rfm::CaseInsensitiveHash.new
         
     | 
| 
      
 284 
     | 
    
         
            +
                  # populate new hash with input, coercing keys to strings
         
     | 
| 
      
 285 
     | 
    
         
            +
                  new_attr.each{|k,v| input_hash.merge! k.to_s=>v}
         
     | 
| 
      
 286 
     | 
    
         
            +
                  # loop thru each layout field, adding data to @mods
         
     | 
| 
      
 287 
     | 
    
         
            +
                  self.class.field_controls.keys.each do |field| 
         
     | 
| 
      
 288 
     | 
    
         
            +
                    field_name = field.to_s
         
     | 
| 
      
 289 
     | 
    
         
            +
                    if input_hash.has_key?(field_name)
         
     | 
| 
      
 290 
     | 
    
         
            +
                      @mods.merge! field_name=>(input_hash[field_name] || '')
         
     | 
| 
      
 291 
     | 
    
         
            +
                    end
         
     | 
| 
      
 292 
     | 
    
         
            +
                  end
         
     | 
| 
      
 293 
     | 
    
         
            +
                  # loop thru each input key-value,
         
     | 
| 
      
 294 
     | 
    
         
            +
                  # creating new attribute if key doesn't exist in model.
         
     | 
| 
      
 295 
     | 
    
         
            +
                  input_hash.each do |k,v| 
         
     | 
| 
      
 296 
     | 
    
         
            +
                    if !self.class.field_controls.keys.include?(k) and self.respond_to?(k)
         
     | 
| 
      
 297 
     | 
    
         
            +
                      self.instance_variable_set("@#{k}", v)
         
     | 
| 
      
 298 
     | 
    
         
            +
                    end
         
     | 
| 
      
 299 
     | 
    
         
            +
                  end            
         
     | 
| 
      
 300 
     | 
    
         
            +
                  self.merge!(@mods) unless @mods == {}
         
     | 
| 
      
 301 
     | 
    
         
            +
                end
         
     | 
| 
      
 302 
     | 
    
         
            +
                
         
     | 
| 
      
 303 
     | 
    
         
            +
                # Mass update of record attributes, with saving.
         
     | 
| 
      
 304 
     | 
    
         
            +
                def update_attributes!(new_attr)
         
     | 
| 
      
 305 
     | 
    
         
            +
                  self.update_attributes(new_attr)
         
     | 
| 
      
 306 
     | 
    
         
            +
                  self.save!
         
     | 
| 
      
 307 
     | 
    
         
            +
                end
         
     | 
| 
      
 308 
     | 
    
         
            +
                
         
     | 
| 
      
 309 
     | 
    
         
            +
                # Save record modifications to database (with callbacks & validations). If record cannot be saved will raise error.
         
     | 
| 
      
 310 
     | 
    
         
            +
                def save!
         
     | 
| 
      
 311 
     | 
    
         
            +
                  #return unless @mods.size > 0
         
     | 
| 
      
 312 
     | 
    
         
            +
                  raise "Record Invalid" unless valid? rescue nil
         
     | 
| 
      
 313 
     | 
    
         
            +
                  if @record_id
         
     | 
| 
      
 314 
     | 
    
         
            +
                    self.update
         
     | 
| 
      
 315 
     | 
    
         
            +
                  else
         
     | 
| 
      
 316 
     | 
    
         
            +
                    self.create
         
     | 
| 
      
 317 
     | 
    
         
            +
                  end
         
     | 
| 
      
 318 
     | 
    
         
            +
                end
         
     | 
| 
      
 319 
     | 
    
         
            +
                
         
     | 
| 
      
 320 
     | 
    
         
            +
            	  # Same as save!, but will not raise error.
         
     | 
| 
      
 321 
     | 
    
         
            +
                def save
         
     | 
| 
      
 322 
     | 
    
         
            +
                  save!
         
     | 
| 
      
 323 
     | 
    
         
            +
                rescue
         
     | 
| 
      
 324 
     | 
    
         
            +
                  (self.errors[:base] rescue []) << $!
         
     | 
| 
      
 325 
     | 
    
         
            +
                  return nil
         
     | 
| 
      
 326 
     | 
    
         
            +
                end
         
     | 
| 
      
 327 
     | 
    
         
            +
            	  
         
     | 
| 
      
 328 
     | 
    
         
            +
            		# Just like Layout#save_if_not_modified, but with callbacks & validations.
         
     | 
| 
      
 329 
     | 
    
         
            +
                def save_if_not_modified
         
     | 
| 
      
 330 
     | 
    
         
            +
                  update(@mod_id) if @mods.size > 0
         
     | 
| 
      
 331 
     | 
    
         
            +
                end    
         
     | 
| 
      
 332 
     | 
    
         
            +
                
         
     | 
| 
      
 333 
     | 
    
         
            +
                # Delete record from database, with callbacks & validations.
         
     | 
| 
      
 334 
     | 
    
         
            +
              	def destroy
         
     | 
| 
      
 335 
     | 
    
         
            +
              	  return unless record_id
         
     | 
| 
      
 336 
     | 
    
         
            +
              	  run_callbacks :destroy do
         
     | 
| 
      
 337 
     | 
    
         
            +
              	    self.class.delete(record_id)
         
     | 
| 
      
 338 
     | 
    
         
            +
              	    @destroyed = true
         
     | 
| 
      
 339 
     | 
    
         
            +
              	    @mods.clear
         
     | 
| 
      
 340 
     | 
    
         
            +
            	    end
         
     | 
| 
      
 341 
     | 
    
         
            +
            	    self.freeze
         
     | 
| 
      
 342 
     | 
    
         
            +
              	  #self
         
     | 
| 
      
 343 
     | 
    
         
            +
            	  end
         
     | 
| 
      
 344 
     | 
    
         
            +
            	  
         
     | 
| 
      
 345 
     | 
    
         
            +
            	  def destroyed?
         
     | 
| 
      
 346 
     | 
    
         
            +
            	  	@destroyed
         
     | 
| 
      
 347 
     | 
    
         
            +
            	  end
         
     | 
| 
      
 348 
     | 
    
         
            +
            	  
         
     | 
| 
      
 349 
     | 
    
         
            +
            		# For ActiveModel compatibility
         
     | 
| 
      
 350 
     | 
    
         
            +
            		def to_model
         
     | 
| 
      
 351 
     | 
    
         
            +
            			self
         
     | 
| 
      
 352 
     | 
    
         
            +
            		end
         
     | 
| 
      
 353 
     | 
    
         
            +
            		
         
     | 
| 
      
 354 
     | 
    
         
            +
            		def persisted?
         
     | 
| 
      
 355 
     | 
    
         
            +
            			record_id ? true : false
         
     | 
| 
      
 356 
     | 
    
         
            +
            		end
         
     | 
| 
      
 357 
     | 
    
         
            +
            		
         
     | 
| 
      
 358 
     | 
    
         
            +
            		def to_key
         
     | 
| 
      
 359 
     | 
    
         
            +
            			record_id ? [record_id] : nil
         
     | 
| 
      
 360 
     | 
    
         
            +
            		end
         
     | 
| 
      
 361 
     | 
    
         
            +
            		
         
     | 
| 
      
 362 
     | 
    
         
            +
            		def to_param
         
     | 
| 
      
 363 
     | 
    
         
            +
            			record_id
         
     | 
| 
      
 364 
     | 
    
         
            +
            		end
         
     | 
| 
      
 365 
     | 
    
         
            +
                
         
     | 
| 
      
 366 
     | 
    
         
            +
            	
         
     | 
| 
      
 367 
     | 
    
         
            +
              protected # Base
         
     | 
| 
      
 368 
     | 
    
         
            +
              
         
     | 
| 
      
 369 
     | 
    
         
            +
              	def self.create_from_new(*args)
         
     | 
| 
      
 370 
     | 
    
         
            +
              	  layout.create(*args)[0]
         
     | 
| 
      
 371 
     | 
    
         
            +
              	end
         
     | 
| 
      
 372 
     | 
    
         
            +
              
         
     | 
| 
      
 373 
     | 
    
         
            +
                # shunt for callbacks when not using ActiveModel
         
     | 
| 
      
 374 
     | 
    
         
            +
                def callback_deadend (*args)
         
     | 
| 
      
 375 
     | 
    
         
            +
                  yield  #(*args)
         
     | 
| 
      
 376 
     | 
    
         
            +
                end
         
     | 
| 
      
 377 
     | 
    
         
            +
                
         
     | 
| 
      
 378 
     | 
    
         
            +
                def create
         
     | 
| 
      
 379 
     | 
    
         
            +
                  #return unless @mods.size > 0
         
     | 
| 
      
 380 
     | 
    
         
            +
                  run_callbacks :create do
         
     | 
| 
      
 381 
     | 
    
         
            +
                    return unless @mods.size > 0
         
     | 
| 
      
 382 
     | 
    
         
            +
              	    merge_rfm_result self.class.create_from_new(@mods)
         
     | 
| 
      
 383 
     | 
    
         
            +
              	  end
         
     | 
| 
      
 384 
     | 
    
         
            +
              	  self
         
     | 
| 
      
 385 
     | 
    
         
            +
              	end
         
     | 
| 
      
 386 
     | 
    
         
            +
              	
         
     | 
| 
      
 387 
     | 
    
         
            +
                def update(mod_id=nil)
         
     | 
| 
      
 388 
     | 
    
         
            +
                  #return unless @mods.size > 0 and record_id
         
     | 
| 
      
 389 
     | 
    
         
            +
                  return false unless record_id
         
     | 
| 
      
 390 
     | 
    
         
            +
              	  run_callbacks :update do
         
     | 
| 
      
 391 
     | 
    
         
            +
              	    return unless @mods.size > 0
         
     | 
| 
      
 392 
     | 
    
         
            +
              	    unless mod_id
         
     | 
| 
      
 393 
     | 
    
         
            +
              	      # regular save
         
     | 
| 
      
 394 
     | 
    
         
            +
              	      merge_rfm_result self.class.send :edit, record_id, @mods
         
     | 
| 
      
 395 
     | 
    
         
            +
            	      else
         
     | 
| 
      
 396 
     | 
    
         
            +
            	        # save_if_not_modified
         
     | 
| 
      
 397 
     | 
    
         
            +
            	        merge_rfm_result self.class.send :edit, record_id, @mods, :modification_id=>mod_id
         
     | 
| 
      
 398 
     | 
    
         
            +
                    end
         
     | 
| 
      
 399 
     | 
    
         
            +
              	  end
         
     | 
| 
      
 400 
     | 
    
         
            +
              	  self
         
     | 
| 
      
 401 
     | 
    
         
            +
              	end
         
     | 
| 
      
 402 
     | 
    
         
            +
              	
         
     | 
| 
      
 403 
     | 
    
         
            +
              	def merge_rfm_result(result_record)
         
     | 
| 
      
 404 
     | 
    
         
            +
                  return unless @mods.size > 0
         
     | 
| 
      
 405 
     | 
    
         
            +
                  @record_id ||= result_record.record_id
         
     | 
| 
      
 406 
     | 
    
         
            +
                  self.merge! result_record
         
     | 
| 
      
 407 
     | 
    
         
            +
                  @mods.clear
         
     | 
| 
      
 408 
     | 
    
         
            +
                  self || {}
         
     | 
| 
      
 409 
     | 
    
         
            +
                end
         
     | 
| 
      
 410 
     | 
    
         
            +
                
         
     | 
| 
      
 411 
     | 
    
         
            +
              end # Base
         
     | 
| 
      
 412 
     | 
    
         
            +
             
     | 
| 
      
 413 
     | 
    
         
            +
            end # Rfm
         
     | 
| 
      
 414 
     | 
    
         
            +
             
     | 
| 
      
 415 
     | 
    
         
            +
             
     | 
| 
      
 416 
     | 
    
         
            +
             
     |