xaviershay-kamel 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +29 -0
- data/Rakefile +11 -0
- data/lib/kamel.rb +1 -0
- data/lib/kamel/overlay.rb +55 -0
- data/spec/kamel/overlay_spec.rb +56 -0
- data/spec/xpath_matchers.rb +105 -0
- metadata +67 -0
data/README.textile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
h1. Kamel
|
2
|
+
|
3
|
+
Create KML files for tasty overlays on google earth and google maps
|
4
|
+
|
5
|
+
<pre><code>gem install kamel --source http://gems.github.com/</code></pre>
|
6
|
+
|
7
|
+
h2. Usage
|
8
|
+
|
9
|
+
<pre><code>require 'rubygems'
|
10
|
+
require 'kamel'
|
11
|
+
|
12
|
+
overlay = Kamel::Overlay.new
|
13
|
+
overlay.name = 'Melbourne Train Stations'
|
14
|
+
[
|
15
|
+
["Flinders St", -37.818078, 144.966811],
|
16
|
+
["Southern Cross", -37.818358, 144.952417],
|
17
|
+
].each do |name, lat, lng|
|
18
|
+
overlay.placemark!(
|
19
|
+
:name => name,
|
20
|
+
:description => "This is a train station",
|
21
|
+
:location => {:lng => lng, :lat => lat},
|
22
|
+
:icon => "http://www.uksa.org/images/about/train-icon.gif"
|
23
|
+
)
|
24
|
+
end
|
25
|
+
puts overlay.to_kml</code></pre>
|
26
|
+
|
27
|
+
h2. Author
|
28
|
+
|
29
|
+
Xavier Shay ("http://rhnh.net":http://rhnh.net)
|
data/Rakefile
ADDED
data/lib/kamel.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'kamel/overlay'
|
@@ -0,0 +1,55 @@
|
|
1
|
+
begin
|
2
|
+
require 'kml'
|
3
|
+
rescue LoadError
|
4
|
+
puts "You must have ruby_kml either installed to use Kamel - either as a gem or available in your path"
|
5
|
+
puts "gem install xaviershay-ruby_kml --source http://gems.github.com"
|
6
|
+
exit
|
7
|
+
end
|
8
|
+
|
9
|
+
module Kamel
|
10
|
+
class Overlay
|
11
|
+
attr_accessor :prefix
|
12
|
+
attr_accessor :name
|
13
|
+
attr_accessor :placemarks
|
14
|
+
|
15
|
+
def initialize(prefix = '')
|
16
|
+
self.prefix = prefix.to_s
|
17
|
+
self.placemarks = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def placemark!(attributes)
|
21
|
+
self.placemarks << attributes
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_kml
|
25
|
+
doc = KML::Document.new
|
26
|
+
doc.name = self.name unless self.name.to_s.length == 0
|
27
|
+
self.icons.each_with_index {|icon, index|
|
28
|
+
doc.styles << KML::Style.new(
|
29
|
+
:id => [prefix, 'style', index].join('-'),
|
30
|
+
:icon_style => KML::IconStyle.new(
|
31
|
+
:icon => KML::Icon.new(:href => icon)
|
32
|
+
)
|
33
|
+
)
|
34
|
+
}
|
35
|
+
self.placemarks.each do |placemark|
|
36
|
+
attrs = {}
|
37
|
+
attrs[:name] = placemark[:name].to_s unless placemark[:name].nil?
|
38
|
+
attrs[:description] = placemark[:description].to_s unless placemark[:description].nil?
|
39
|
+
attrs[:geometry] = KML::Point.new(:coordinates => placemark[:location]) unless placemark[:location].nil?
|
40
|
+
attrs[:style_url] = '#' + [prefix, 'style', self.icons.index(placemark[:icon])].join('-') unless placemark[:icon].nil?
|
41
|
+
doc.features << KML::Placemark.new(attrs)
|
42
|
+
end
|
43
|
+
|
44
|
+
kml = KMLFile.new
|
45
|
+
kml.objects << doc
|
46
|
+
kml.render
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def icons
|
52
|
+
self.placemarks.collect {|x| x[:icon]}.compact.uniq.sort
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
|
2
|
+
require 'rubygems'
|
3
|
+
require 'spec'
|
4
|
+
require 'kamel'
|
5
|
+
require File.dirname(__FILE__) + '/../xpath_matchers'
|
6
|
+
|
7
|
+
|
8
|
+
require 'rexml/document'
|
9
|
+
require 'rexml/element'
|
10
|
+
|
11
|
+
describe Kamel::Overlay, '#to_kml' do
|
12
|
+
setup do
|
13
|
+
@overlay = Kamel::Overlay.new('test')
|
14
|
+
@overlay.placemark!(:name => 'placemark-1', :location => {:lat => 1, :lng => 2}, :description => 'Place 1', :icon => 'icon-1.png')
|
15
|
+
@overlay.placemark!(:name => 'placemark-2', :location => "3,4", :description => 'Place 2', :icon => 'icon-1.png')
|
16
|
+
@overlay.placemark!(:name => 'placemark-3', :location => [5,6,7], :icon => 'icon-2.png')
|
17
|
+
@doc = @overlay.to_kml
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'outputs one style block for each unique icon' do
|
21
|
+
@doc.should have_nodes("/kml/Document/Style", 2)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'outputs one placemark block for each placemark' do
|
25
|
+
@doc.should have_nodes("/kml/Document/Placemark", 3)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'records the name of each placemark' do
|
29
|
+
@doc.should match_xpath("/kml/Document/Placemark[1]/name", "placemark-1")
|
30
|
+
@doc.should match_xpath("/kml/Document/Placemark[2]/name", "placemark-2")
|
31
|
+
@doc.should match_xpath("/kml/Document/Placemark[3]/name", "placemark-3")
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'records the description of each placemark if it is provided' do
|
35
|
+
#TODO Figure out how to check for CDATA
|
36
|
+
@doc.should have_xpath("/kml/Document/Placemark[1]/description")
|
37
|
+
@doc.should have_xpath("/kml/Document/Placemark[2]/description")
|
38
|
+
@doc.should_not have_xpath("/kml/Document/Placemark[3]/description")
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'records the location of each placemark' do
|
42
|
+
@doc.should match_xpath("/kml/Document/Placemark[1]/Point/coordinates", "2,1")
|
43
|
+
@doc.should match_xpath("/kml/Document/Placemark[2]/Point/coordinates", "3,4")
|
44
|
+
@doc.should match_xpath("/kml/Document/Placemark[3]/Point/coordinates", "5,6,7")
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'records a styleUrl that matches up to the style block for the given icon' do
|
48
|
+
doc = REXML::Document.new(@doc)
|
49
|
+
style_ids = REXML::XPath.match(doc, "/kml/Document/Style/IconStyle/Icon/href").inject({}) {|a,v|
|
50
|
+
a.update(v.text => '#' + v.parent.parent.parent.attribute('id').value)
|
51
|
+
}
|
52
|
+
@doc.should match_xpath("/kml/Document/Placemark[1]/styleUrl", style_ids['icon-1.png'])
|
53
|
+
@doc.should match_xpath("/kml/Document/Placemark[2]/styleUrl", style_ids['icon-1.png'])
|
54
|
+
@doc.should match_xpath("/kml/Document/Placemark[3]/styleUrl", style_ids['icon-2.png'])
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# http://blog.wolfman.com/articles/2008/01/02/xpath-matchers-for-rspec
|
2
|
+
|
3
|
+
module Spec
|
4
|
+
module Matchers
|
5
|
+
|
6
|
+
# check if the xpath exists one or more times
|
7
|
+
class HaveXpath
|
8
|
+
def initialize(xpath)
|
9
|
+
@xpath = xpath
|
10
|
+
end
|
11
|
+
|
12
|
+
def matches?(response)
|
13
|
+
@response = response
|
14
|
+
doc = response.is_a?(REXML::Document) ? response : REXML::Document.new(@response)
|
15
|
+
match = REXML::XPath.match(doc, @xpath)
|
16
|
+
not match.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def failure_message
|
20
|
+
"Did not find expected xpath #{@xpath}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def negative_failure_message
|
24
|
+
"Did find unexpected xpath #{@xpath}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def description
|
28
|
+
"match the xpath expression #{@xpath}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def have_xpath(xpath)
|
33
|
+
HaveXpath.new(xpath)
|
34
|
+
end
|
35
|
+
|
36
|
+
# check if the xpath has the specified value
|
37
|
+
# value is a string and there must be a single result to match its
|
38
|
+
# equality against
|
39
|
+
class MatchXpath
|
40
|
+
def initialize(xpath, val)
|
41
|
+
@xpath = xpath
|
42
|
+
@val= val
|
43
|
+
end
|
44
|
+
|
45
|
+
def matches?(response)
|
46
|
+
@response = response
|
47
|
+
doc = response.is_a?(REXML::Document) ? response : REXML::Document.new(@response)
|
48
|
+
ok= true
|
49
|
+
REXML::XPath.each(doc, @xpath) do |e|
|
50
|
+
@actual_val= case e
|
51
|
+
when REXML::Attribute
|
52
|
+
e.to_s
|
53
|
+
when REXML::Element
|
54
|
+
e.text
|
55
|
+
else
|
56
|
+
e.to_s
|
57
|
+
end
|
58
|
+
return false unless @val == @actual_val
|
59
|
+
end
|
60
|
+
return ok
|
61
|
+
end
|
62
|
+
|
63
|
+
def failure_message
|
64
|
+
"The xpath #{@xpath} did not have the value '#{@val}'\nIt was '#{@actual_val}'"
|
65
|
+
end
|
66
|
+
|
67
|
+
def description
|
68
|
+
"match the xpath expression #{@xpath} with #{@val}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def match_xpath(xpath, val)
|
73
|
+
MatchXpath.new(xpath, val)
|
74
|
+
end
|
75
|
+
|
76
|
+
# checks if the given xpath occurs num times
|
77
|
+
class HaveNodes #:nodoc:
|
78
|
+
def initialize(xpath, num)
|
79
|
+
@xpath= xpath
|
80
|
+
@num = num
|
81
|
+
end
|
82
|
+
|
83
|
+
def matches?(response)
|
84
|
+
@response = response
|
85
|
+
doc = response.is_a?(REXML::Document) ? response : REXML::Document.new(@response)
|
86
|
+
match = REXML::XPath.match(doc, @xpath)
|
87
|
+
@num_found= match.size
|
88
|
+
@num_found == @num
|
89
|
+
end
|
90
|
+
|
91
|
+
def failure_message
|
92
|
+
"Did not find expected number of nodes #{@num} in xpath #{@xpath}\nFound #{@num_found}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def description
|
96
|
+
"match the number of nodes #{@num}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def have_nodes(xpath, num)
|
101
|
+
HaveNodes.new(xpath, num)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xaviershay-kamel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Xavier Shay
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-06-08 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: xaviershay-ruby_kml
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.0.0
|
23
|
+
version:
|
24
|
+
description: Create KML files for tasty overlays on google earth and google maps
|
25
|
+
email: xavier@rhnh.net
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- LICENSE
|
34
|
+
- Rakefile
|
35
|
+
- README.textile
|
36
|
+
- lib/kamel/overlay.rb
|
37
|
+
- lib/kamel.rb
|
38
|
+
- spec/xpath_matchers.rb
|
39
|
+
- spec/kamel/overlay_spec.rb
|
40
|
+
has_rdoc: false
|
41
|
+
homepage: http://github.com/xaviershay/kamel
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.0.1
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Create KML files for tasty overlays on google earth and google maps
|
66
|
+
test_files:
|
67
|
+
- spec/kamel/overlay_spec.rb
|