kamelopard 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZTY5Y2M5MWMyYWE4MGUyNTgxM2VlNzljMzYzMTJlYjkzZmU0NWYxZA==
5
+ data.tar.gz: !binary |-
6
+ M2Y2MmIwNDk4YzIwNGZkMjdjMDVhOTlmYzZlMGMyNzM4N2QxMTJhMg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ OWNkNGFjMGU0NjY3ZTU2MzUxYTg3NWUzOGNiZmI0ZDhmYTY5MTM4NTM2ODhj
10
+ ZmJmNDRhZmYzNzA1OTdjOTMzYTYxZGY4Y2RlMmIzY2ZiMTRiNWVkNmQ4ODU1
11
+ NmYyMTUzODU4NzA0Zjc5NWNhMmU4ZGM5NWJiNmExODRkN2YwZGU=
12
+ data.tar.gz: !binary |-
13
+ NGY5ZTE0NGQyNzA1OTg4NjRlZWIwNzgwMDRlYzNkZDc5ZTIyZWQ5YmE4NjUz
14
+ MWY4NjEwMWMzMGUyMzBlNDFhMzc3Yjc1ZTc5MWE0NjIwYjZmZjM0OTJhNTg5
15
+ ZjJmZGQxNDkzNTU3MmYzMDliZTg0ZGEwNmFhNmI5ZDIyMzcwYTE=
@@ -2,11 +2,53 @@
2
2
  #--
3
3
  # vim:ts=4:sw=4:et:smartindent:nowrap
4
4
  #++
5
- # Classes to manage various KML objects. See
6
- # http://code.google.com/apis/kml/documentation/kmlreference.html for a
7
- # description of KML
8
5
 
9
- # Pretty much everything important is in this module
6
+ # == Description
7
+ # Kamelopard is a gem to create and manipulate Keyhole Markup Language, or KML.
8
+ # See http://code.google.com/apis/kml/documentation/kmlreference.html for a
9
+ # reference on the subject. Within the Kamelopard module are several classes
10
+ # which represent KML objects. To use Kamelopard to create a KML document from
11
+ # scratch, you'll eventually want to create instances of these classes. You can
12
+ # manipulate these instances' attributes and connections to other classes, and
13
+ # in the end, write the result to a KML file. Here's a simple example which
14
+ # creates one placemark in a file called doc.kml:
15
+ #
16
+ # require 'rubygems'
17
+ # require 'kamelopard'
18
+ #
19
+ # f = Kamelopard::Folder.new('Some Folder Name')
20
+ # f << Kamelopard::Placemark('My placemark',
21
+ # :geometry => Kamelopard::Point(1, 2, 3))
22
+ # write_kml_to 'doc.kml'
23
+ #
24
+ # Kamelopard operates as a sort of state machine, with a concept of the
25
+ # "current" document. Newly created objects are appended to the current
26
+ # document. See the DocumentHolder class to learn about switching around
27
+ # between different documents. Note also that whereas tour elements such as
28
+ # FlyTo and Wait are always kept in the order in which they were created, other
29
+ # elements like Styles and Folders might show up in different orders. Since in
30
+ # the final output this doesn't matter (or shouldn't, anyway), this isn't
31
+ # considered a bug, and in fact it makes it easier sometimes, because you don't
32
+ # have to figure out the structure of your document in the proper order at run
33
+ # time.
34
+ #
35
+ # Kamelopard comes with a set of helper functions which it puts in the default
36
+ # namespace. Experienced users will probably choose use these functions to
37
+ # create Kamelopard objects rather than instantiating these classes directly.
38
+ #
39
+ # Objects' attributes are often undocumented, when they correspond directly to
40
+ # a similarly named attribute in the KML object they represent. Refer to the
41
+ # KML reference linked above for more details about these undocumented
42
+ # attributes. Most objects' constructors accept a hash of options you can use
43
+ # to set these attributes, such as the :geometry option used in the sample code
44
+ # above. Kamelopard will complain if you try to set an option it doesn't
45
+ # recognize.
46
+ #
47
+ # Most objects also include a to_kml() method, which returns an XML::Node
48
+ # containing the KML this object represents, including any other objects nested
49
+ # inside. The write_kml_to helper function used above, and other helper
50
+ # functions involved in KML output, generally wrap this method so it rarely
51
+ # gets called directly.
10
52
  module Kamelopard
11
53
  require 'bundler/setup'
12
54
  require 'singleton'
@@ -58,7 +100,7 @@ module Kamelopard
58
100
  @@logger.call(level, mod, msg) unless @@logger.nil? or @@log_level > LogLevels[level]
59
101
  end
60
102
 
61
- def Kamelopard.xml_to_hash(node, fields)
103
+ def Kamelopard.xml_to_hash(node, fields) # :nodoc:
62
104
  result = {}
63
105
  fields.each do |field|
64
106
  begin
@@ -1061,7 +1103,7 @@ module Kamelopard
1061
1103
 
1062
1104
  # Represents KML's Document class.
1063
1105
  class Document < Container
1064
- attr_accessor :flyto_mode, :folders, :tours, :uses_xal, :vsr_actions
1106
+ attr_accessor :flyto_mode, :folders, :tours, :uses_xal, :vsr_actions, :filename
1065
1107
 
1066
1108
  # Is this KML destined for a master LG node, or a slave? True if this
1067
1109
  # is a master node. This defaults to true, so tours that don't need
@@ -1073,11 +1115,20 @@ module Kamelopard
1073
1115
  @folders = []
1074
1116
  @vsr_actions = []
1075
1117
  @master_mode = false
1118
+ @filename = 'doc.kml'
1076
1119
  Kamelopard.log(:info, 'Document', "Adding myself to the document holder")
1077
1120
  DocumentHolder.instance << self
1078
1121
  super
1079
1122
  end
1080
1123
 
1124
+ def make_current
1125
+ Kamelopard::DocumentHolder.instance.set_current self
1126
+ end
1127
+
1128
+ def activate
1129
+ make_current
1130
+ end
1131
+
1081
1132
  # Returns viewsyncrelay actions as a hash
1082
1133
  def get_actions
1083
1134
  {
@@ -1202,6 +1253,12 @@ module Kamelopard
1202
1253
  #! These get printed out in the call to super, in Feature.to_kml()
1203
1254
  #@styles.map do |a| d << a.to_kml unless a.attached? end
1204
1255
 
1256
+ # then misc
1257
+ @features.each do |f|
1258
+ next if f.is_a? Folder or f.is_a? Style or f.is_a? Tour
1259
+ f.to_kml d
1260
+ end
1261
+
1205
1262
  # then folders
1206
1263
  @folders.map do |a|
1207
1264
  a.to_kml(d) unless a.has_parent?
@@ -1685,7 +1742,10 @@ module Kamelopard
1685
1742
  end
1686
1743
 
1687
1744
  # Corresponds to KML's Placemark objects. The geometry attribute requires a
1688
- # descendant of Geometry
1745
+ # descendant of Geometry. *Note:* whereas most objects implicitly add
1746
+ # themselves to the end of the current Document, Placemarks do not. They
1747
+ # must be explicitly added to the Document or other Container they live in,
1748
+ # typically with the Container's << operator.
1689
1749
  class Placemark < Feature
1690
1750
  attr_accessor :name, :geometry, :balloonVisibility
1691
1751
 
@@ -2368,6 +2428,8 @@ module Kamelopard
2368
2428
  }.each do |k, v|
2369
2429
  d = XML::Node.new k.to_s
2370
2430
  d << v.to_s
2431
+ # Don't escape links, because Earth doesn't like that.
2432
+ d.first.output_escaping = false
2371
2433
  x << d
2372
2434
  end
2373
2435
  Kamelopard.kml_array(x, [
@@ -7,22 +7,53 @@ require 'uri'
7
7
  require 'cgi'
8
8
  require 'json'
9
9
 
10
- # Geocoder base class
10
+ # Geocoder base class. You should use a subclass. It is your responsibility to
11
+ # ensure you comply with all API licensing and usage requirements. Kamelopard
12
+ # won't do it for you.
11
13
  class Geocoder
12
14
  attr_accessor :host, :path, :params
13
15
  def initialize
14
16
  @params = {}
15
17
  end
16
18
 
19
+ def processParam(value, key = 'location')
20
+ return ["#{key}=#{value}"] if key == 'key'
21
+ if value.kind_of? Hash then
22
+ p = value.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v)}" }
23
+ else
24
+ p = ["#{CGI.escape(key)}=#{CGI.escape(value)}"]
25
+ end
26
+ return p
27
+ end
28
+
17
29
  def parse_response(r)
18
30
  raise "Unimplemented -- use a child of the Geocoder class"
19
31
  end
20
32
  end
21
33
 
22
- # Some specific geocoding API classes follow. Google's would seem most
23
- # obvious, but since it requires you to display results on a map, ... I didn't
24
- # want to have to evaluate other possible restrictions, or require that they be
25
- # imposed on Kamelopard users.
34
+ class GoogleGeocoder < Geocoder
35
+ attr_reader :api_key, :response_format
36
+
37
+ def initialize(key, response_format = 'json')
38
+ super()
39
+ @proto = 'http'
40
+ @host = 'maps.googleapis.com'
41
+ @path = '/maps/api/geocode'
42
+ @api_key = key
43
+ @response_format = response_format
44
+ end
45
+
46
+ def getURL(params)
47
+ http = Net::HTTP.new(@host)
48
+ u = URI::HTTP.build([nil, @host, nil, "#{@path}/#{@response_format}", params, nil])
49
+
50
+ JSON.parse(Net::HTTP.get u)
51
+ end
52
+
53
+ def lookup(address)
54
+ getURL(processParam(address, 'address').join('&'))
55
+ end
56
+ end
26
57
 
27
58
  class MapquestGeocoder < Geocoder
28
59
  attr_reader :api_key, :response_format
@@ -31,28 +62,38 @@ class MapquestGeocoder < Geocoder
31
62
  super()
32
63
  @proto = 'http'
33
64
  @host = 'www.mapquestapi.com'
34
- @path = '/geocoding/v1/address'
65
+ @path = {
66
+ :address => '/geocoding/v1/address',
67
+ :batch => '/geocoding/v1/batch'
68
+ }
35
69
  @api_key = key
36
70
  @response_format = response_format
37
71
  @params['key'] = @api_key
38
72
  end
39
73
 
74
+ def getURL(args, type)
75
+ raise "Type (#{type}) must be one of #{ @path.keys.map { |a| ":#{a}" }.join(', ')}" unless @path.has_key? type
76
+
77
+ params = @params.map { |k, v| processParam(v, k) }.concat(args).join('&')
78
+
79
+ http = Net::HTTP.new(@host)
80
+ u = URI::HTTP.build([nil, @host, nil, @path[type], params, nil])
81
+
82
+ resp = Net::HTTP.get u
83
+ parse_response resp
84
+ end
85
+
40
86
  # Returns an object built from the JSON result of the lookup, or an exception
41
87
  def lookup(address)
42
88
  # The argument can be a string, in which case PlaceFinder does the parsing
43
89
  # The argument can also be a hash, with several possible keys. See the PlaceFinder documentation for details
44
90
  # http://developer.yahoo.com/geo/placefinder/guide/requests.html
45
- http = Net::HTTP.new(@host)
46
- if address.kind_of? Hash then
47
- p = @params.merge address
48
- else
49
- p = @params.merge( { 'location' => address } )
50
- end
51
- q = p.map { |k,v| "#{ k == 'key' ? k : CGI.escape(k) }=#{ k == 'key' ? v : CGI.escape(v) }" }.join('&')
52
- u = URI::HTTP.build([nil, @host, nil, @path, q, nil])
91
+ return getURL(processParam(address), :address)
92
+ end
53
93
 
54
- resp = Net::HTTP.get u
55
- parse_response resp
94
+ def lookupBatch(addresses)
95
+ # The argument should be an array of the same sorts of values that can be fed to lookup()
96
+ return getURL(addresses.map { |k| processParam(k) }.flatten(1), :batch)
56
97
  end
57
98
 
58
99
  def parse_response(r)