kamelopard 0.0.14 → 0.0.15

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 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)