ProMotion 0.7.8 → 1.0.0

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.
Files changed (91) hide show
  1. data/.gitignore +2 -1
  2. data/.travis.yml +1 -1
  3. data/ProMotion.gemspec +2 -0
  4. data/README.md +51 -449
  5. data/Rakefile +11 -1
  6. data/app/screens/basic_screen.rb +0 -24
  7. data/lib/ProMotion/cocoatouch/{NavigationController.rb → navigation_controller.rb} +0 -0
  8. data/lib/ProMotion/cocoatouch/split_view_controller.rb +29 -0
  9. data/lib/ProMotion/cocoatouch/tab_bar_controller.rb +43 -0
  10. data/lib/ProMotion/cocoatouch/{TableViewCell.rb → table_view_cell.rb} +0 -1
  11. data/lib/ProMotion/cocoatouch/{TableViewController.rb → table_view_controller.rb} +0 -0
  12. data/lib/ProMotion/cocoatouch/{ViewController.rb → view_controller.rb} +6 -1
  13. data/lib/ProMotion/{screen_helpers → containers}/split_screen.rb +0 -2
  14. data/lib/ProMotion/containers/tabs.rb +95 -0
  15. data/lib/ProMotion/delegate/delegate.rb +2 -13
  16. data/lib/ProMotion/delegate/{delegate_helper.rb → delegate_module.rb} +29 -16
  17. data/lib/ProMotion/delegate/delegate_notifications.rb +17 -8
  18. data/lib/ProMotion/delegate/delegate_parent.rb +11 -0
  19. data/lib/ProMotion/extensions/conversions.rb +20 -0
  20. data/lib/ProMotion/{helpers/logger.rb → logger.rb} +0 -0
  21. data/lib/ProMotion/map/map_screen.rb +6 -0
  22. data/lib/ProMotion/map/map_screen_annotation.rb +56 -0
  23. data/lib/ProMotion/map/map_screen_module.rb +207 -0
  24. data/lib/ProMotion/{push_notifications → push_notification}/push_notification.rb +13 -6
  25. data/lib/ProMotion/{screens → screen}/screen.rb +1 -1
  26. data/lib/ProMotion/{screens/_screen_module.rb → screen/screen_module.rb} +76 -51
  27. data/lib/ProMotion/{screen_helpers → screen}/screen_navigation.rb +8 -12
  28. data/lib/ProMotion/{screens/_tables → table/cell}/table_view_cell_module.rb +18 -27
  29. data/lib/ProMotion/table/data/table_data.rb +98 -0
  30. data/lib/ProMotion/table/extensions/indexable.rb +9 -0
  31. data/lib/ProMotion/table/extensions/refreshable.rb +45 -0
  32. data/lib/ProMotion/table/extensions/searchable.rb +61 -0
  33. data/lib/ProMotion/table/grouped_table.rb +9 -0
  34. data/lib/ProMotion/table/grouped_table_screen.rb +6 -0
  35. data/lib/ProMotion/table/table.rb +312 -0
  36. data/lib/ProMotion/table/table_screen.rb +6 -0
  37. data/lib/ProMotion/{screens/_compatibility → thirdparty}/formotion_screen.rb +18 -5
  38. data/lib/ProMotion/version.rb +1 -1
  39. data/lib/ProMotion/view/styling.rb +137 -0
  40. data/lib/ProMotion/web/web_screen.rb +6 -0
  41. data/lib/ProMotion/web/web_screen_module.rb +155 -0
  42. data/resources/WebScreen.html +6 -0
  43. data/resources/test.jpeg +0 -0
  44. data/spec/functional/func_map_screen_spec.rb +105 -0
  45. data/spec/functional/func_screen_spec.rb +54 -7
  46. data/spec/functional/func_searchable_table_spec.rb +1 -1
  47. data/spec/functional/func_tab_bar_spec.rb +78 -0
  48. data/spec/functional/func_table_screen_spec.rb +61 -14
  49. data/spec/functional/func_web_screen_spec.rb +51 -0
  50. data/spec/helpers/map_screen.rb +51 -0
  51. data/spec/helpers/present_screen.rb +26 -0
  52. data/spec/helpers/tab_screen.rb +4 -0
  53. data/spec/helpers/table_screen.rb +12 -3
  54. data/spec/helpers/table_screen_formotion.rb +25 -0
  55. data/spec/helpers/table_screen_indexable.rb +13 -0
  56. data/spec/helpers/test_delegate.rb +28 -0
  57. data/spec/helpers/web_screen.rb +22 -0
  58. data/spec/unit/delegate_spec.rb +53 -4
  59. data/spec/unit/map_spec.rb +48 -0
  60. data/spec/unit/screen_helpers_spec.rb +24 -16
  61. data/spec/unit/screen_spec.rb +22 -18
  62. data/spec/unit/split_screen_in_tab_bar_spec.rb +2 -2
  63. data/spec/unit/split_screen_open_screen_spec.rb +15 -10
  64. data/spec/unit/split_screen_spec.rb +2 -2
  65. data/spec/unit/tab_spec.rb +41 -0
  66. data/spec/unit/tables/formotion_screen_spec.rb +16 -0
  67. data/spec/unit/tables/table_indexable_spec.rb +12 -0
  68. data/spec/unit/tables/table_module_spec.rb +24 -9
  69. data/spec/unit/tables/table_screen_spec.rb +1 -1
  70. data/spec/unit/tables/table_view_cell_spec.rb +9 -8
  71. data/spec/unit/view_helper_spec.rb +2 -2
  72. data/spec/unit/web_spec.rb +106 -0
  73. metadata +96 -35
  74. data/lib/ProMotion/cocoatouch/SplitViewController.rb +0 -23
  75. data/lib/ProMotion/helpers/console.rb +0 -29
  76. data/lib/ProMotion/helpers/measure_helper.rb +0 -20
  77. data/lib/ProMotion/helpers/system_helper.rb +0 -29
  78. data/lib/ProMotion/helpers/view_helper.rb +0 -82
  79. data/lib/ProMotion/screen_helpers/screen_elements.rb +0 -36
  80. data/lib/ProMotion/screen_helpers/screen_tabs.rb +0 -95
  81. data/lib/ProMotion/screens/_table_screen_module.rb +0 -47
  82. data/lib/ProMotion/screens/_tables/_refreshable_table.rb +0 -45
  83. data/lib/ProMotion/screens/_tables/_searchable_table.rb +0 -60
  84. data/lib/ProMotion/screens/_tables/_sectioned_table.rb +0 -5
  85. data/lib/ProMotion/screens/_tables/_table.rb +0 -169
  86. data/lib/ProMotion/screens/_tables/grouped_table.rb +0 -16
  87. data/lib/ProMotion/screens/_tables/plain_table.rb +0 -17
  88. data/lib/ProMotion/screens/_tables/table_data.rb +0 -175
  89. data/lib/ProMotion/screens/behaves_like_screen.rb +0 -10
  90. data/lib/ProMotion/screens/table_screen.rb +0 -16
  91. data/spec/unit/ios_version_spec.rb +0 -28
@@ -0,0 +1,6 @@
1
+ module ProMotion
2
+ class TableScreen < TableViewController
3
+ include ProMotion::ScreenModule
4
+ include ProMotion::Table
5
+ end
6
+ end
@@ -2,7 +2,7 @@ module ProMotion
2
2
  if defined?(Formotion) && defined?(Formotion::FormController)
3
3
  class FormotionScreen < Formotion::FormController
4
4
  include ProMotion::ScreenModule
5
-
5
+
6
6
  def self.new(args = {})
7
7
  s = self.alloc.initWithStyle(UITableViewStyleGrouped)
8
8
  s.on_create(args) if s.respond_to?(:on_create)
@@ -15,7 +15,9 @@ module ProMotion
15
15
  PM.logger.error "PM::FormotionScreen requires a `table_data` method or form: to be passed into `new`."
16
16
  end
17
17
 
18
+ t = s.title # Formotion kills the title when you request tableView.
18
19
  s.tableView.allowsSelectionDuringEditing = true
20
+ s.title = t
19
21
 
20
22
  s
21
23
  end
@@ -26,6 +28,15 @@ module ProMotion
26
28
  self.form.controller = self
27
29
  self.tableView.reloadData
28
30
  end
31
+
32
+ def screen_setup
33
+ self.title = self.class.send(:get_title)
34
+ end
35
+
36
+ def loadView
37
+ super
38
+ self.send(:on_load) if self.respond_to?(:on_load)
39
+ end
29
40
 
30
41
  def viewDidLoad
31
42
  super
@@ -34,21 +45,23 @@ module ProMotion
34
45
 
35
46
  def viewWillAppear(animated)
36
47
  super
37
- self.view_will_appear(animated) if self.respond_to?(:view_will_appear)
48
+ self.view_will_appear(animated) if self.respond_to?("view_will_appear:")
38
49
  end
39
50
 
40
51
  def viewDidAppear(animated)
41
52
  super
42
- self.view_did_appear(animated) if self.respond_to?(:view_did_appear)
53
+ self.view_did_appear(animated) if self.respond_to?("view_did_appear:")
43
54
  end
44
55
 
45
56
  def viewWillDisappear(animated)
46
- self.view_will_disappear(animated) if self.respond_to?(:view_will_disappear)
57
+ self.view_will_disappear(animated) if self.respond_to?("view_will_disappear:")
47
58
  super
48
59
  end
49
60
 
50
61
  def viewDidDisappear(animated)
51
- self.view_did_disappear(animated) if self.respond_to?(:view_did_disappear)
62
+ if self.respond_to?("view_did_disappear:")
63
+ self.view_did_disappear(animated)
64
+ end
52
65
  super
53
66
  end
54
67
 
@@ -1,3 +1,3 @@
1
1
  module ProMotion
2
- VERSION = "0.7.8" unless defined?(ProMotion::VERSION)
2
+ VERSION = "1.0.0" unless defined?(ProMotion::VERSION)
3
3
  end
@@ -0,0 +1,137 @@
1
+ module ProMotion
2
+ module Styling
3
+ include Conversions
4
+
5
+ def set_attributes(element, args = {})
6
+ args.each { |k, v| set_attribute(element, k, v) }
7
+ element
8
+ end
9
+
10
+ def set_attribute(element, k, v)
11
+ return element unless element
12
+
13
+ if v.is_a?(Hash) && element.respond_to?(k)
14
+ sub_element = element.send(k)
15
+ set_attributes(sub_element, v) if sub_element
16
+ elsif element.respond_to?("#{k}=")
17
+ element.send("#{k}=", v)
18
+ elsif v.is_a?(Array) && element.respond_to?("#{k}") && element.method("#{k}").arity == v.length
19
+ element.send("#{k}", *v)
20
+ else
21
+ # Doesn't respond. Check if snake case.
22
+ if k.to_s.include?("_")
23
+ set_attribute(element, objective_c_method_name(k), v)
24
+ end
25
+ end
26
+ element
27
+ end
28
+
29
+ def set_easy_attributes(parent, element, args={})
30
+ attributes = {}
31
+
32
+ if args[:resize]
33
+ attributes[:autoresizingMask] = UIViewAutoresizingNone
34
+ args[:resize].each { |r| attributes[:autoresizingMask] |= map_resize_symbol(r) }
35
+ end
36
+
37
+ if [:left, :top, :width, :height].select{ |a| args[a] && args[a] != :auto }.length == 4
38
+ attributes[:frame] = CGRectMake(args[:left], args[:top], args[:width], args[:height])
39
+ end
40
+
41
+ set_attributes element, attributes
42
+ element
43
+ end
44
+
45
+ def content_height(view)
46
+ height = 0
47
+ view.subviews.each do |sub_view|
48
+ next if sub_view.isHidden
49
+ y = sub_view.frame.origin.y
50
+ h = sub_view.frame.size.height
51
+ if (y + h) > height
52
+ height = y + h
53
+ end
54
+ end
55
+ height
56
+ end
57
+
58
+ def closest_parent(type, this_view = nil)
59
+ # iterate up the view hierarchy to find the parent element of "type" containing this view
60
+ this_view ||= view_or_self.superview
61
+ while this_view != nil do
62
+ return this_view if this_view.is_a? type
63
+ this_view = this_view.superview
64
+ end
65
+ nil
66
+ end
67
+
68
+ def add(element, attrs = {})
69
+ add_to view_or_self, element, attrs
70
+ end
71
+ alias :add_element :add
72
+ alias :add_view :add
73
+
74
+ def remove(element)
75
+ element.removeFromSuperview
76
+ element = nil
77
+ end
78
+ alias :remove_element :remove
79
+ alias :remove_view :remove
80
+
81
+ def add_to(parent_element, element, attrs = {})
82
+ parent_element.addSubview element
83
+ if attrs && attrs.length > 0
84
+ set_attributes(element, attrs)
85
+ set_easy_attributes(parent_element, element, attrs)
86
+ end
87
+ element
88
+ end
89
+
90
+ def view_or_self
91
+ self.respond_to?(:view) ? self.view : self
92
+ end
93
+
94
+ # These three color methods are stolen from BubbleWrap.
95
+ def rgb_color(r,g,b)
96
+ rgba_color(r,g,b,1)
97
+ end
98
+
99
+ def rgba_color(r,g,b,a)
100
+ r,g,b = [r,g,b].map { |i| i / 255.0}
101
+ UIColor.colorWithRed(r, green: g, blue:b, alpha:a)
102
+ end
103
+
104
+ def hex_color(str)
105
+ hex_color = str.gsub("#", "")
106
+ case hex_color.size
107
+ when 3
108
+ colors = hex_color.scan(%r{[0-9A-Fa-f]}).map{ |el| (el * 2).to_i(16) }
109
+ when 6
110
+ colors = hex_color.scan(%r<[0-9A-Fa-f]{2}>).map{ |el| el.to_i(16) }
111
+ else
112
+ raise ArgumentError
113
+ end
114
+
115
+ if colors.size == 3
116
+ rgb_color(colors[0], colors[1], colors[2])
117
+ else
118
+ raise ArgumentError
119
+ end
120
+ end
121
+
122
+ protected
123
+
124
+ def map_resize_symbol(symbol)
125
+ @_resize_symbols ||= {
126
+ left: UIViewAutoresizingFlexibleLeftMargin,
127
+ right: UIViewAutoresizingFlexibleRightMargin,
128
+ top: UIViewAutoresizingFlexibleTopMargin,
129
+ bottom: UIViewAutoresizingFlexibleBottomMargin,
130
+ width: UIViewAutoresizingFlexibleWidth,
131
+ height: UIViewAutoresizingFlexibleHeight
132
+ }
133
+ @_resize_symbols[symbol] || symbol
134
+ end
135
+
136
+ end
137
+ end
@@ -0,0 +1,6 @@
1
+ module ProMotion
2
+ class WebScreen < ViewController
3
+ include ProMotion::ScreenModule
4
+ include ProMotion::WebScreenModule
5
+ end
6
+ end
@@ -0,0 +1,155 @@
1
+ module ProMotion
2
+ module WebScreenModule
3
+
4
+ attr_accessor :webview, :external_links, :detector_types
5
+
6
+ def screen_setup
7
+ check_content_data
8
+ self.external_links ||= false
9
+ end
10
+
11
+ def on_init
12
+
13
+ self.detector_types ||= UIDataDetectorTypeNone
14
+ if self.detector_types.is_a? Array
15
+ detectors = UIDataDetectorTypeNone
16
+ self.detector_types.each { |dt| detectors |= map_detector_symbol(dt) }
17
+ self.detector_types = detectors
18
+ end
19
+
20
+ self.webview ||= add UIWebView.new, {
21
+ frame: CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height),
22
+ resize: [ :width, :height ],
23
+ delegate: self,
24
+ data_detector_types: self.detector_types
25
+ }
26
+
27
+ set_initial_content
28
+ end
29
+
30
+ def web
31
+ self.webview
32
+ end
33
+
34
+ def set_initial_content
35
+ return unless self.respond_to?(:content)
36
+ content.is_a?(NSURL) ? open_url(content) : set_content(content)
37
+ end
38
+
39
+ def set_content(content)
40
+ content_path = File.join(NSBundle.mainBundle.resourcePath, content)
41
+
42
+ if File.exists? content_path
43
+ content_string = File.read content_path
44
+ content_base_url = NSURL.fileURLWithPath NSBundle.mainBundle.resourcePath
45
+
46
+ self.web.loadHTMLString(convert_retina_images(content_string), baseURL:content_base_url)
47
+ else
48
+ # We assume the user wants to load an arbitrary string into the web view
49
+ self.web.loadHTMLString(content, baseURL:nil)
50
+ end
51
+ end
52
+
53
+ def open_url(url)
54
+ request = NSURLRequest.requestWithURL(
55
+ url.is_a?(NSURL) ? url : NSURL.URLWithString(url)
56
+ )
57
+ web.loadRequest request
58
+ end
59
+
60
+ def convert_retina_images(content)
61
+ #Convert images over to retina if the images exist.
62
+ if UIScreen.mainScreen.bounds.respondsToSelector('displayLinkWithTarget:selector:') && UIScreen.mainScreen.bounds.scale == 2.0 # Thanks BubbleWrap! https://github.com/rubymotion/BubbleWrap/blob/master/motion/core/device/ios/screen.rb#L9
63
+ content.gsub!(/src=['"](.*?)\.(jpg|gif|png)['"]/) do |img|
64
+ if File.exists?(File.join(NSBundle.mainBundle.resourcePath, "#{$1}@2x.#{$2}"))
65
+ # Create a UIImage to get the width and height of hte @2x image
66
+ tmp_image = UIImage.imageNamed("/#{$1}@2x.#{$2}")
67
+ new_width = tmp_image.size.width / 2
68
+ new_height = tmp_image.size.height / 2
69
+
70
+ img = "src=\"#{$1}@2x.#{$2}\" width=\"#{new_width}\" height=\"#{new_height}\""
71
+ end
72
+ end
73
+ end
74
+ content
75
+ end
76
+
77
+ def check_content_data
78
+ PM.logger.error "Missing #content method in WebScreen #{self.class.to_s}." unless self.respond_to?(:content)
79
+ end
80
+
81
+ def html
82
+ self.webview.stringByEvaluatingJavaScriptFromString("document.documentElement.outerHTML")
83
+ end
84
+
85
+ def evaluate(js)
86
+ self.webview.stringByEvaluatingJavaScriptFromString(js)
87
+ end
88
+
89
+ def current_url
90
+ evaluate('document.URL')
91
+ end
92
+
93
+ # Navigation
94
+ def can_go_back; web.canGoBack; end
95
+ def can_go_forward; web.canGoForward; end
96
+ def back; web.goBack if can_go_back; end
97
+ def forward; web.goForward if can_go_forward; end
98
+ def refresh; web.reload; end
99
+ def stop; web.stopLoading; end
100
+ alias :reload :refresh
101
+
102
+ def open_in_chrome(inRequest)
103
+ # Add pod 'OpenInChrome' to your Rakefile if you want links to open in chrom for users.
104
+ chrome_controller = OpenInChromeController.sharedInstance
105
+ return open_in_safari(inRequest) unless chrome_controller.isChromeInstalled
106
+ chrome_controller.open_in_chrome(inRequest.URL)
107
+ end
108
+
109
+ def open_in_safari(inRequest)
110
+ #Open UIWebView delegate links in Safari.
111
+ UIApplication.sharedApplication.openURL(inRequest.URL)
112
+ end
113
+
114
+ #UIWebViewDelegate Methods - Camelcase
115
+ def webView(inWeb, shouldStartLoadWithRequest:inRequest, navigationType:inType)
116
+ if self.external_links == true && inType == UIWebViewNavigationTypeLinkClicked
117
+ if defined?(OpenInChromeController)
118
+ open_in_chrome inRequest
119
+ else
120
+ open_in_safari inRequest
121
+ end
122
+ return false #don't allow the web view to load the link.
123
+ end
124
+
125
+ load_request_enable = true #return true on default for local file loading.
126
+ load_request_enable = !!on_request(inRequest, inType) if self.respond_to?(:on_request)
127
+ load_request_enable
128
+ end
129
+
130
+ def webViewDidStartLoad(webView)
131
+ load_started if self.respond_to?(:load_started)
132
+ end
133
+
134
+ def webViewDidFinishLoad(webView)
135
+ load_finished if self.respond_to?(:load_finished)
136
+ end
137
+
138
+ def webView(webView, didFailLoadWithError:error)
139
+ load_failed(error) if self.respond_to?("load_failed:")
140
+ end
141
+
142
+ protected
143
+
144
+ def map_detector_symbol(symbol)
145
+ {
146
+ phone: UIDataDetectorTypePhoneNumber,
147
+ link: UIDataDetectorTypeLink,
148
+ address: UIDataDetectorTypeAddress,
149
+ event: UIDataDetectorTypeCalendarEvent,
150
+ all: UIDataDetectorTypeAll
151
+ }[symbol] || UIDataDetectorTypeNone
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,6 @@
1
+ <html>
2
+ <head></head>
3
+ <body>
4
+ <h1>Test</h1>
5
+ </body>
6
+ </html>
Binary file
@@ -0,0 +1,105 @@
1
+ describe "ProMotion::TestMapScreen functionality" do
2
+ tests PM::TestMapScreen
3
+
4
+ # Override controller to properly instantiate
5
+ def controller
6
+ rotate_device to: :portrait, button: :bottom
7
+ @map ||= TestMapScreen.new(nav_bar: true)
8
+ @map.will_appear
9
+ @map.navigation_controller
10
+ end
11
+
12
+ after do
13
+ @map = nil
14
+ end
15
+
16
+ it "should have a navigation bar" do
17
+ @map.navigationController.should.be.kind_of(UINavigationController)
18
+ end
19
+
20
+ it "should have the map properly centered" do
21
+ center_coordinate = @map.center
22
+ center_coordinate.latitude.should.be.close 35.090648651123, 0.001
23
+ center_coordinate.longitude.should.be.close -82.965972900391, 0.001
24
+ end
25
+
26
+ it "should move the map center" do
27
+ @map.center = {latitude: 35.07496, longitude: -82.95916, animated: true}
28
+
29
+ wait 0.75 do
30
+ center_coordinate = @map.center
31
+ center_coordinate.latitude.should.be.close 35.07496, 0.001
32
+ center_coordinate.longitude.should.be.close -82.95916, 0.001
33
+ end
34
+ end
35
+
36
+ it "should select an annotation" do
37
+ @map.selected_annotations.should == nil
38
+ @map.select_annotation @map.annotations.first
39
+ wait 0.75 do
40
+ @map.selected_annotations.count.should == 1
41
+ end
42
+ end
43
+
44
+ it "should select an annotation by index" do
45
+ @map.selected_annotations.should == nil
46
+ @map.select_annotation_at 2
47
+ wait 0.75 do
48
+ @map.selected_annotations.count.should == 1
49
+ @map.selected_annotations[0].should == @map.promotion_annotation_data[2]
50
+ end
51
+ end
52
+
53
+ it "should select another annotation and check that the title is correct" do
54
+ @map.selected_annotations.should == nil
55
+ @map.select_annotation @map.annotations[1]
56
+ wait 0.75 do
57
+ @map.selected_annotations.count.should == 1
58
+ end
59
+
60
+ @map.selected_annotations.first.title.should == "Turtleback Falls"
61
+ @map.selected_annotations.first.subtitle.should == "Nantahala National Forest"
62
+
63
+ end
64
+
65
+ it "should deselect selected annotations" do
66
+ @map.select_annotation @map.annotations.last
67
+ wait 0.75 do
68
+ # @map.selected_annotations.count.should == 1
69
+ end
70
+
71
+ @map.deselect_annotations
72
+ wait 0.75 do
73
+ @map.selected_annotations.should == nil
74
+ end
75
+ end
76
+
77
+ it "should add an annotation and be able to zoom immediately" do
78
+ ann = {
79
+ longitude: -82.966093558105,
80
+ latitude: 35.092520895652,
81
+ title: "Something Else"
82
+ }
83
+ @map.annotations.count.should == 5
84
+ @map.add_annotation ann
85
+ @map.annotations.count.should == 6
86
+ @map.set_region @map.region(coordinate: @map.annotations.last.coordinate, span: [0.05, 0.05])
87
+ @map.select_annotation @map.annotations.last
88
+ end
89
+
90
+ it "should be able to overwrite all annotations" do
91
+ anns = [{
92
+ longitude: -122.029620,
93
+ latitude: 37.331789,
94
+ title: "My Cool Pin"
95
+ },{
96
+ longitude: -80.8498118 ,
97
+ latitude: 35.2187218,
98
+ title: "My Cool Pin"
99
+ }]
100
+ @map.annotations.count.should == 5
101
+ @map.add_annotations anns
102
+ @map.annotations.count.should == 2
103
+ end
104
+
105
+ end