ginjo-rfm 3.0.4 → 3.0.5

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NmQyNjY1ZmFlZWQyMjdiYTRiMDE5NWNiY2VhMjNjOGMwNzJhZTMwMA==
4
+ NWQ1ODlhYTI5ZDM2OTkxNDc3MGE5MGEyZjM4YWI2YTA0MzIyMTM1OA==
5
5
  data.tar.gz: !binary |-
6
- ZjYzOWNlMzAyNDRiNmZmNmM1ODczYTgyNmFjZDdlZDAyZGRhZWNkZQ==
6
+ NzgwMmY2OTA3OTZkMzYxZTQ2ZmE2NzY1YmFkYmJhMzUxOGEwMGNlYw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZjgxYThhYjcxM2E2OTE5ZTJmNjk2NGYyZmQ4ZWNlYWQ2OTAxN2RmN2ZmNjBl
10
- OTg1NWEzZWVkYzhiODNlMTg2NzEwYWQ4MjNhZjg5MjYwZWZiMzEwNGY5OWQ3
11
- ZjUyZTExNDVhNGVkZmE5YWM1OTFlNGVmOGFmMzJhZGFhZmU0OGE=
9
+ NzVmNWUwZmNlNTAxNmIwNzNlNDkxMDU4NTE3YWY1YzU1ZDg0MDIzZjFhNWVj
10
+ MTNkZmJhN2QxNDBmOTY4NzE1MzRhMjU4MjIzNGZlODNlZjVhYmVlNTUwMWRk
11
+ YzU0ZDBkNDRhNjk3MjFhNDBjNzRmNjBjODU5NmY4MmQ1MjgwZjE=
12
12
  data.tar.gz: !binary |-
13
- ODNmN2M4ODgzZWVmNWM2NGZhYjhlMWIxMDk5NzAyNTlhMTU3N2QyOTZkM2Q2
14
- Zjg3MjBiMDZkYzc1MTUyY2RjYjVkMmEwMjc0M2E3YTNiNmEwZTI1YzE3OTRi
15
- ZjRlNDQxYjVhMWMzZjg3OGVhMzM0MTAxNzY5YTNjMDhjOTUyMTQ=
13
+ ODZlYmU4ZTAwMmI3M2FjZDA0ZjE5MDk0NzNhNmNkODJmOTc5NmUxZmI0YzU5
14
+ OTUxNTM4OTUxZjA5NTdkOTE0ZTZlNjAxMGI3NWMxY2FiOTJmNTJhODQxNDhh
15
+ N2IxN2VjOWQ0ZDlhMTU0NzNjYjU3NGI3ZTJhOTk0NDM3MGQ1NDM=
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## Ginjo-Rfm 3.0.5
4
+
5
+ * Fixed parser handling of `<field>` element that's missing a `<data>` element.
6
+ * Fixed coercion of repeating field data.
7
+ * Fixed case where special characters in Filemaker data yielded array instead of string (sax parsing split text).
8
+ * Fixed various bugs in metadata parsing.
9
+ * Detached resultset from Rfm::MetaData::Field instance, now attaching only ResultsetMeta to Field.
10
+ * Fixed ruby-prof rake task.
11
+ * Updated deprecated rspec 2 specs, will now work with rspec 2 or 3.
12
+ * Added more specs for some recently found bugs and for sax parser.
13
+ * Fixed broken ActiveModel Lint specs in Ruby 2.1.
14
+ * General refinements & cleanup.
15
+ * Optimizations to sax_parser.
16
+ * Fixed typo in field.rb that was causing bugs.
17
+
3
18
  ## Ginjo-Rfm 3.0.4
4
19
 
5
20
  * Corrected reference to @meta in fmpxmllayout.yml. Specs now passing for Layout#load\_layout.
data/lib/rfm.rb CHANGED
@@ -59,12 +59,8 @@ module Rfm
59
59
  end
60
60
 
61
61
  def_delegators 'Rfm::Factory', :servers, :server, :db, :database, :layout
62
- def_delegators 'Rfm::SaxParser', :backend, :backend=
63
- def_delegators 'Rfm::SaxParser::Handler', :get_backend
64
62
  def_delegators 'Rfm::Config', :config, :get_config, :config_clear
65
63
  def_delegators 'Rfm::Resultset', :load_data
66
- alias_method :parser, :backend
67
- alias_method :parser=, :backend=
68
64
 
69
65
  def models(*args)
70
66
  Rfm::Base
@@ -75,9 +71,7 @@ module Rfm
75
71
  Rfm::Base
76
72
  Rfm::Factory.modelize(*args)
77
73
  end
78
-
79
- #attr_accessor :log
80
-
74
+
81
75
  def logger
82
76
  @@logger ||= get_config[:logger] || Logger.new(STDOUT).tap {|l| l.formatter = proc {|severity, datetime, progname, msg| "#{datetime}: Rfm-#{severity} #{msg}\n"}}
83
77
  end
@@ -88,17 +82,26 @@ module Rfm
88
82
  @@logger = obj
89
83
  end
90
84
 
85
+ # DEFAULT_CLASS = CaseInsensitiveHash
86
+ # TEMPLATE_PREFIX = File.join(File.dirname(__FILE__), 'rfm/utilities/sax/')
87
+ # TEMPLATES = {
88
+ # :fmpxmllayout => 'fmpxmllayout.yml',
89
+ # :fmresultset => 'fmresultset.yml',
90
+ # :fmpxmlresult => 'fmpxmlresult.yml',
91
+ # :none => nil
92
+ # }
91
93
 
94
+ PARSER_DEFAULTS = {
95
+ :default_class => CaseInsensitiveHash,
96
+ :template_prefix => File.join(File.dirname(__FILE__), 'rfm/utilities/sax/'),
97
+ :templates => {
98
+ :fmpxmllayout => 'fmpxmllayout.yml',
99
+ :fmresultset => 'fmresultset.yml',
100
+ :fmpxmlresult => 'fmpxmlresult.yml',
101
+ :none => nil
102
+ }
103
+ }
92
104
 
93
105
  extend self
94
106
 
95
- SaxParser.default_class = CaseInsensitiveHash
96
- SaxParser.template_prefix = File.join(File.dirname(__FILE__), 'rfm/utilities/sax/')
97
- SaxParser.templates.merge!({
98
- :fmpxmllayout => 'fmpxmllayout.yml',
99
- :fmresultset => 'fmresultset.yml',
100
- :fmpxmlresult => 'fmpxmlresult.yml',
101
- :none => nil
102
- })
103
-
104
107
  end # Rfm
data/lib/rfm/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.4
1
+ 3.0.5
@@ -1,13 +1,15 @@
1
- require 'delegate'
1
+ #require 'delegate'
2
2
  module Rfm
3
3
  module Metadata
4
4
 
5
5
  class Datum #< DelegateClass(Field)
6
6
 
7
7
  def get_mapped_name(name, resultset)
8
+ #puts ["\nDATUM#get_mapped_name", "name: #{name}", "mapping: #{resultset.layout.field_mapping.to_yaml}"]
8
9
  (resultset && resultset.layout && resultset.layout.field_mapping[name]) || name
9
10
  end
10
11
 
12
+ # NOT sure what this method is for. Can't find a reference to it.
11
13
  def main_callback(cursor)
12
14
  resultset = cursor.top.object
13
15
  name = get_mapped_name(@attributes['name'].to_s, resultset)
@@ -16,7 +18,7 @@ module Rfm
16
18
  cursor.parent.object[name.downcase] = field.coerce(data)
17
19
  end
18
20
 
19
- def portal_callback(cursor)
21
+ def portal_field_element_close_callback(cursor)
20
22
  resultset = cursor.top.object
21
23
  table, name = @attributes['name'].to_s.split('::')
22
24
  #puts ['DATUM_portal_callback_01', table, name].join(', ')
@@ -29,14 +31,15 @@ module Rfm
29
31
  end
30
32
 
31
33
  # Should return value only.
32
- def handler_callback(cursor)
34
+ def field_element_close_callback(cursor)
33
35
  record = cursor.parent.object
34
36
  resultset = cursor.top.object
35
37
 
36
38
  name = get_mapped_name(@attributes['name'].to_s, resultset)
37
39
  field = resultset.field_meta[name]
38
- data = @attributes['data']
40
+ data = @attributes['data'] #'data'
39
41
  #puts ["\nDATUM", name, record.class, resultset.class, data]
42
+ #puts ["\nDATUM", self.to_yaml]
40
43
  record[name] = field.coerce(data)
41
44
  end
42
45
 
@@ -1,8 +1,10 @@
1
+ require 'forwardable'
2
+
1
3
  module Rfm
2
4
  module Metadata
3
5
 
4
6
  # The Field object represents a single FileMaker field. It *does not hold the data* in the field. Instead,
5
- # it serves as a source of metadata about the field. For example, if you're script is trying to be highly
7
+ # it serves as a source of metadata about the field. For example, if your script is trying to be highly
6
8
  # dynamic about its field access, it may need to determine the data type of a field at run time. Here's
7
9
  # how:
8
10
  #
@@ -60,11 +62,14 @@ module Rfm
60
62
  class Field
61
63
 
62
64
  attr_reader :name, :result, :type, :max_repeats, :global
63
- meta_attr_accessor :resultset
65
+ meta_attr_accessor :resultset_meta
66
+ def_delegator :resultset_meta, :layout_object, :layout_object
64
67
  # Initializes a field object. You'll never need to do this. Instead, get your Field objects from
65
68
  # Resultset::field_meta
66
69
  def initialize(attributes)
67
- _attach_as_instance_variables attributes
70
+ if attributes && attributes.size > 0
71
+ _attach_as_instance_variables attributes
72
+ end
68
73
  self
69
74
  end
70
75
 
@@ -72,15 +77,20 @@ module Rfm
72
77
  # type of the field. You'll never need to do this: Rfm does it automatically for you when you
73
78
  # access field data through the Record object.
74
79
  def coerce(value)
75
- return nil if (value.nil? or value.empty?)
80
+ case
81
+ when (value.nil? or value.empty?); return nil
82
+ when value.is_a?(Array); return value.collect {|v| coerce(v)}
83
+ when value.is_a?(Hash); return coerce(value.values[0])
84
+ end
85
+
76
86
  case result
77
87
  when "text" then value
78
88
  when "number" then BigDecimal.new(value.to_s)
79
- when "date" then Date.strptime(value, resultset.date_format)
80
- when "time" then DateTime.strptime("1/1/-4712 #{value}", "%m/%d/%Y #{resultset.time_format}")
81
- when "timestamp" then DateTime.strptime(value, resultset.timestamp_format)
89
+ when "date" then Date.strptime(value, resultset_meta.date_format)
90
+ when "time" then DateTime.strptime("1/1/-4712 #{value}", "%m/%d/%Y #{resultset_meta.time_format}")
91
+ when "timestamp" then DateTime.strptime(value, resultset_meta.timestamp_format)
82
92
  when "container" then
83
- resultset_meta = resultset.instance_variable_get(:@meta)
93
+ #resultset_meta = resultset.instance_variable_get(:@meta)
84
94
  if resultset_meta && resultset_meta['doctype'] && value.to_s[/\?/]
85
95
  URI.parse(resultset_meta['doctype'].last.to_s).tap{|uri| uri.path, uri.query = value.split('?')}
86
96
  else
@@ -88,22 +98,27 @@ module Rfm
88
98
  end
89
99
  else nil
90
100
  end
91
- # rescue
92
- # puts("ERROR in Field#coerce:", name, value, result, $!)
93
- # nil
101
+ rescue
102
+ puts("ERROR in Field#coerce:", name, value, result, resultset_meta.timestamp_format, $!)
103
+ nil
94
104
  end
95
105
 
96
106
  def get_mapped_name
97
- (resultset && resultset.layout && resultset.layout.field_mapping[name]) || name
107
+ #(resultset_meta && resultset_meta.layout && resultset_meta.layout.field_mapping[name]) || name
108
+ layout_object.field_mapping[name] || name
98
109
  end
99
110
 
100
- def main_callback(cursor)
101
- self.resultset = cursor.top.object
102
- resultset.field_meta[get_mapped_name.to_s.downcase] = self
111
+ def field_definition_element_close_callback(cursor)
112
+ #self.resultset = cursor.top.object
113
+ #resultset_meta = resultset.instance_variable_get(:@meta)
114
+ self.resultset_meta = cursor.top.object.instance_variable_get(:@meta)
115
+ #puts ["\nFIELD#field_definition_element_close_callback", resultset_meta]
116
+ resultset_meta.field_meta[get_mapped_name.to_s.downcase] = self
103
117
  end
104
118
 
105
- def portal_callback(cursor)
106
- self.resultset = cursor.top.object
119
+ def relatedset_field_definition_element_close_callback(cursor)
120
+ #self.resultset = cursor.top.object
121
+ self.resultset_meta = cursor.top.object.instance_variable_get(:@meta)
107
122
  cursor.parent.object[get_mapped_name.split('::').last.to_s.downcase] = self
108
123
  #puts ['FIELD_portal_callback', name, cursor.parent.object.object_id, cursor.parent.tag, cursor.parent.object[name.split('::').last.to_s.downcase]].join(', ')
109
124
  end
@@ -24,62 +24,60 @@ module Rfm
24
24
  class FieldControl
25
25
  attr_reader :name, :style, :value_list_name
26
26
  meta_attr_accessor :layout_meta
27
+
28
+ FIELD_CONTROL_STYLE_MAP = {
29
+ 'EDITTEXT' => :edit_box,
30
+ 'POPUPMENU' => :popup_menu,
31
+ 'CHECKBOX' => :checkbox_set,
32
+ 'RADIOBUTTONS' => :radio_button_set,
33
+ 'POPUPLIST' => :popup_list,
34
+ 'CALENDAR' => :calendar,
35
+ 'SCROLLTEXT' => :scrollable,
36
+ }
27
37
 
28
- def initialize(attributes, meta)
38
+ # def initialize(_attributes, meta)
39
+ # puts ["\nFieldControl#initialize", "_attributes: #{_attributes}", "meta: #{meta.class}"]
40
+ # self.layout_meta = meta
41
+ # _attach_as_instance_variables(_attributes) if _attributes
42
+ # self
43
+ # end
44
+
45
+ def initialize(meta)
46
+ #puts ["\nFieldControl#initialize", "meta: #{meta.class}"]
29
47
  self.layout_meta = meta
30
- _attach_as_instance_variables attributes
31
48
  self
32
49
  end
33
50
 
34
- # Handle manual attachment of STYLE element.
35
- def handle_style_element(attributes)
36
- _attach_as_instance_variables attributes, :key_translator=>method(:translate_value_list_key), :value_translator=>method(:translate_style_value)
37
- end
51
+ # # Handle manual attachment of STYLE element.
52
+ # def handle_style_element(attributes)
53
+ # _attach_as_instance_variables attributes, :key_translator=>method(:translate_value_list_key), :value_translator=>method(:translate_style_value)
54
+ # end
55
+ #
56
+ # def translate_style_value(key, val)
57
+ # #puts ["TRANSLATE_STYLE", raw].join(', ')
58
+ # {
59
+ # 'EDITTEXT' => :edit_box,
60
+ # 'POPUPMENU' => :popup_menu,
61
+ # 'CHECKBOX' => :checkbox_set,
62
+ # 'RADIOBUTTONS' => :radio_button_set,
63
+ # 'POPUPLIST' => :popup_list,
64
+ # 'CALENDAR' => :calendar,
65
+ # 'SCROLLTEXT' => :scrollable,
66
+ # }[val] || val
67
+ # end
38
68
 
39
- def translate_style_value(raw)
40
- #puts ["TRANSLATE_STYLE", raw].join(', ')
41
- {
42
- 'EDITTEXT' => :edit_box,
43
- 'POPUPMENU' => :popup_menu,
44
- 'CHECKBOX' => :checkbox_set,
45
- 'RADIOBUTTONS' => :radio_button_set,
46
- 'POPUPLIST' => :popup_list,
47
- 'CALENDAR' => :calendar,
48
- 'SCROLLTEXT' => :scrollable,
49
- }[raw] || raw
50
- end
51
-
52
- def translate_value_list_key(raw)
53
- {'valuelist'=>'value_list_name'}[raw] || raw
54
- end
69
+ # def translate_value_list_key(raw)
70
+ # {'valuelist'=>'value_list_name'}[raw] || raw
71
+ # end
55
72
 
56
73
  def value_list
57
74
  layout_meta.value_lists[value_list_name]
58
75
  end
59
-
60
- # def initialize(name, style, value_list_name, value_list)
61
- # @name = name
62
- # case style
63
- # when "EDITTEXT"
64
- # @style = :edit_box
65
- # when "POPUPMENU"
66
- # @style = :popup_menu
67
- # when "CHECKBOX"
68
- # @style = :checkbox_set
69
- # when "RADIOBUTTONS"
70
- # @style = :radio_button_set
71
- # when "POPUPLIST"
72
- # @style = :popup_list
73
- # when "CALENDAR"
74
- # @style = :calendar
75
- # when "SCROLLTEXT"
76
- # @style = :scrollable
77
- # else
78
- # nil
79
- # end
80
- # @value_list_name = value_list_name
81
- # rfm_metaclass.instance_variable_set :@value_list, value_list
82
- # end
76
+
77
+ def element_close_handler #(_cursor)
78
+ @type = FIELD_CONTROL_STYLE_MAP[@type] || @type
79
+ layout_meta.receive_field_control(self)
80
+ end
83
81
 
84
82
  end
85
83
  end
@@ -22,11 +22,16 @@ module Rfm
22
22
  self['value_lists'] ||= CaseInsensitiveHash.new
23
23
  end
24
24
 
25
- def handle_new_field_control(attributes)
26
- name = attributes['name']
27
- field_control = FieldControl.new(attributes, self)
28
- field_controls[get_mapped_name(name)] = field_control
29
- end
25
+ # def handle_new_field_control(attributes)
26
+ # name = attributes['name']
27
+ # field_control = FieldControl.new(attributes, self)
28
+ # field_controls[get_mapped_name(name)] = field_control
29
+ # end
30
+
31
+ def receive_field_control(fc)
32
+ #name = fc.name
33
+ field_controls[get_mapped_name(fc.name)] = fc
34
+ end
30
35
 
31
36
  # Should this be in FieldControl object?
32
37
  def get_mapped_name(name)
@@ -54,12 +54,21 @@ module Rfm
54
54
  portal_meta ? portal_meta.keys : []
55
55
  end
56
56
 
57
- def handle_new_field(attributes)
58
- f = Field.new(attributes)
59
- # TODO: Re-enable these when you stop using the before_close callback.
60
- # name = attributes['name']
61
- # self[name] = f
62
- end
57
+ # def handle_new_field(attributes)
58
+ # f = Field.new(attributes)
59
+ # # TODO: Re-enable these when you stop using the before_close callback.
60
+ # # name = attributes['name']
61
+ # # self[name] = f
62
+ # end
63
+
64
+ def layout_object
65
+ self['layout_object']
66
+ end
67
+
68
+ def attach_layout_object_from_cursor(cursor)
69
+ self['layout_object'] = cursor.top.object.layout
70
+ #puts ["\nRESULTSET_META#metadata_element_close_callback", self['layout_object']]
71
+ end
63
72
 
64
73
  end
65
74
  end
data/lib/rfm/record.rb CHANGED
@@ -147,7 +147,7 @@ module Rfm
147
147
  self.merge!(@mods) unless @mods == {}
148
148
  @loaded = true
149
149
  end
150
- _attach_as_instance_variables args[1]
150
+ _attach_as_instance_variables(args[1]) if args[1].is_a? Hash
151
151
  #@loaded = true
152
152
  self
153
153
  end
data/lib/rfm/resultset.rb CHANGED
@@ -49,9 +49,9 @@ module Rfm
49
49
 
50
50
 
51
51
  class << self
52
- def load_data(data)
52
+ def load_data(data, object=self.new)
53
53
  Rfm::Connection
54
- Rfm::SaxParser.parse(data, :fmresultset, Rfm::Resultset.new)
54
+ Rfm::SaxParser.parse(data, :fmresultset, object)
55
55
  end
56
56
  end
57
57
 
@@ -111,6 +111,7 @@ module Rfm
111
111
  @meta ||= Metadata::ResultsetMeta.new
112
112
  end
113
113
 
114
+ # Deprecated on 7/29/2014. Stop using.
114
115
  def handle_new_record(attributes)
115
116
  r = Rfm::Record.new(self, attributes, {})
116
117
  self << r
@@ -118,14 +119,15 @@ module Rfm
118
119
  end
119
120
 
120
121
  def end_datasource_element_callback(cursor)
121
- %w(date_format time_format timestamp_format).each{|f| convert_date_time_format(eval(f))}
122
+ %w(date_format time_format timestamp_format).each{|f| convert_date_time_format(send(f))}
123
+ @meta.attach_layout_object_from_cursor(cursor)
122
124
  end
123
125
 
124
126
  private
125
127
 
126
- def check_for_errors(code=@meta['error'].to_i, raise_401=state[:raise_401])
127
- #puts ["\nRESULTSET#check_for_errors", code, raise_401]
128
- raise Rfm::Error.getError(code) if code != 0 && (code != 401 || raise_401)
128
+ def check_for_errors(error_code=@meta['error'].to_i, raise_401=state[:raise_401])
129
+ #puts ["\nRESULTSET#check_for_errors", "meta[:error] #{@meta[:error]}", "error_code: #{error_code}", "raise_401: #{raise_401}"]
130
+ raise Rfm::Error.getError(error_code) if error_code != 0 && (error_code != 401 || raise_401)
129
131
  end
130
132
 
131
133
  def convert_date_time_format(fm_format)