ginjo-rfm 3.0.4 → 3.0.5

Sign up to get free protection for your applications and to get access to all the features.
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)