Class: Rosemary::Element

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Validations, Comparable
Defined in:
lib/rosemary/element.rb

Overview

This is a virtual parent class for the OSM objects Node, Way and Relation.

Direct Known Subclasses

BoundingBox, Node, Relation, Way

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs = {}) ⇒ Element

:nodoc:

Raises:

  • (NotImplementedError)

46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/rosemary/element.rb', line 46

def initialize(attrs = {}) #:nodoc:
  raise NotImplementedError.new('Element is a virtual base class for the Node, Way, and Relation classes') if self.class == Rosemary::Element
  attrs = {'version' => 1, 'uid' => 1}.merge(attrs.stringify_keys!)
  @id         = attrs['id'].to_i if attrs['id']
  @version    = attrs['version'].to_i
  @uid        = attrs['uid'].to_i
  @user       = attrs['user']
  @timestamp  = Time.parse(attrs['timestamp']) rescue nil
  @changeset  = attrs['changeset'].to_i
  @tags       = Tags.new
  add_tags(attrs['tag']) if attrs['tag']
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object

All other methods are mapped so its easy to access tags: For instance obj.name is the same as obj.tags. This works for getting and setting tags.

node = Rosemary::Node.new
node.add_tags( 'highway' => 'residential', 'name' => 'Main Street' )
node.highway                   #=> 'residential'
node.highway = 'unclassified'  #=> 'unclassified'
node.name                      #=> 'Main Street'

In addition methods of the form key? are used to check boolean tags. For instance oneway can be 'true' or 'yes' or '1', all meaning the same.

way.oneway?

will check this. It returns true if the value of this key is either 'true', 'yes' or '1'.


227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/rosemary/element.rb', line 227

def method_missing(method, *args)
  methodname = method.to_s
  if methodname.slice(-1, 1) == '='
    if args.size != 1
      raise ArgumentError.new("wrong number of arguments (#{args.size} for 1)")
    end
    tags[methodname.chop] = args[0]
  elsif methodname.slice(-1, 1) == '?'
    if args.size != 0
      raise ArgumentError.new("wrong number of arguments (#{args.size} for 0)")
    end
    tags[methodname.chop] =~ /^(true|yes|1)$/
  else
    if args.size != 0
      raise ArgumentError.new("wrong number of arguments (#{args.size} for 0)")
    end
    tags[methodname]
  end
end

Instance Attribute Details

#changesetObject

The changeset the last change of this object was made with.


33
34
35
# File 'lib/rosemary/element.rb', line 33

def changeset
  @changeset
end

#idFixnum

Unique ID

Returns:

  • (Fixnum)

    id of this element


9
10
11
# File 'lib/rosemary/element.rb', line 9

def id
  @id
end

#tagsObject (readonly)

Tags for this object


36
37
38
# File 'lib/rosemary/element.rb', line 36

def tags
  @tags
end

#timestampTime

Last change of this object (as read from file, it is not updated by operations to this object)

Returns:

  • (Time)

    last change of this object.


30
31
32
# File 'lib/rosemary/element.rb', line 30

def timestamp
  @timestamp
end

#uidObject

The user id of the user who last edited this object (as read from file, it is not updated by operations to this object) API 0.6 and above only


25
26
27
# File 'lib/rosemary/element.rb', line 25

def uid
  @uid
end

#userRosemary::User

The user who last edited this element (as read from file, it is not updated by operations to this object)

Returns:


20
21
22
# File 'lib/rosemary/element.rb', line 20

def user
  @user
end

#versionFixnum

The version of this object (as read from file, it is not updated by operations to this object) API 0.6 and above only

Returns:

  • (Fixnum)

    the current version


15
16
17
# File 'lib/rosemary/element.rb', line 15

def version
  @version
end

Class Method Details

.from_api(id, api = Rosemary::API.new) ⇒ Object

Get Rosemary::Element from API

Parameters:

  • id (Fixnum)

    the id of the element to load from the API

Raises:

  • (NotImplementedError)

41
42
43
44
# File 'lib/rosemary/element.rb', line 41

def self.from_api(id, api=Rosemary::API.new) #:nodoc:
    raise NotImplementedError.new('Element is a virtual base class for the Node, Way, and Relation classes') if self.class == Rosemary::Element
    api.get_object(type, id)
end

.from_xml(xml) ⇒ Object


252
253
254
# File 'lib/rosemary/element.rb', line 252

def self.from_xml(xml)
  Parser.call(xml, :xml)
end

Instance Method Details

#<=>(another_element) ⇒ Object


59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rosemary/element.rb', line 59

def <=>(another_element)
  attribute_list.each do |attrib|
    next if self.send(attrib) == another_element.send(attrib)

    if self.send(attrib) < another_element.send(attrib)
      return -1
    else
      return 1
    end
  end
  0
end

#[](key) ⇒ Object

Get tag value


107
108
109
# File 'lib/rosemary/element.rb', line 107

def [](key)
  tags[key]
end

#[]=(key, value) ⇒ Object

Set tag


112
113
114
# File 'lib/rosemary/element.rb', line 112

def []=(key, value)
  tags[key] = value
end

#add_tags(new_tags) ⇒ Object

Add one or more tags to this object.

call-seq: add_tags(Hash) -> OsmObject


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/rosemary/element.rb', line 120

def add_tags(new_tags)
  case new_tags
  when Array # Called with an array
    # Call recursively for each entry
    new_tags.each do |tag_hash|
      add_tags(tag_hash)
    end
  when Hash # Called with a hash
    #check if it is weird {'k' => 'key', 'v' => 'value'} syntax
    if (new_tags.size == 2 && new_tags.keys.include?('k') && new_tags.keys.include?('v'))
      # call recursively with values from k and v keys.
      add_tags({new_tags['k'] => new_tags['v']})
    else
      # OK, this seems to be a proper ruby hash with a single entry
      new_tags.each do |k,v|
        self.tags[k] = v
      end
    end
  end
  self    # return self so calls can be chained
end

#attribute_listObject

The list of attributes for this object


85
86
87
# File 'lib/rosemary/element.rb', line 85

def attribute_list # :nodoc:
  [:id, :version, :uid, :user, :timestamp, :changeset, :tags]
end

#attributesObject

Returns a hash of all non-nil attributes of this object.

Keys of this hash are :id, :user, and :timestamp. For a Node also :lon and :lat.

call-seq: attributes -> Hash


97
98
99
100
101
102
103
104
# File 'lib/rosemary/element.rb', line 97

def attributes
  attrs = Hash.new
  attribute_list.each do |attribute|
    value = self.send(attribute)
    attrs[attribute] = value unless value.nil?
  end
  attrs
end

#get_history_from_api(api = Rosemary::API.new) ⇒ Object

Get the history of this object from the API.

The optional parameter is an Rosemary::API object. If none is specified the default OSM API is used.

Returns an array of Rosemary::Node, Rosemary::Way, or Rosemary::Relation objects with all the versions.


205
206
207
# File 'lib/rosemary/element.rb', line 205

def get_history_from_api(api=Rosemary::API.new)
  api.get_history(type, self.id.to_i)
end

#get_relations_from_api(api = Rosemary::API.new) ⇒ Object

Get all relations from the API that have his object as members.

The optional parameter is an Rosemary::API object. If none is specified the default OSM API is used.

Returns an array of Relation objects or an empty array.


194
195
196
# File 'lib/rosemary/element.rb', line 194

def get_relations_from_api(api=Rosemary::API.new)
  api.get_relations_referring_to_object(type, self.id.to_i)
end

#initialize_copy(from) ⇒ Object


247
248
249
250
# File 'lib/rosemary/element.rb', line 247

def initialize_copy(from)
  super
  @tags = from.tags.dup
end

#is_tagged?Boolean

Has this object any tags?

Returns:

  • (Boolean)

    has any tags?


158
159
160
# File 'lib/rosemary/element.rb', line 158

def is_tagged?
  ! @tags.empty?
end

#shape(geom, attributes) ⇒ Object

Create a new GeoRuby::Shp4r::ShpRecord with the geometry of this object and the given attributes.

This only works if the GeoRuby library is included.

geom

Geometry

attributes

Hash with attributes

call-seq: shape(attributes) -> GeoRuby::Shp4r::ShpRecord

Example:

require 'rubygems'
require 'geo_ruby'
node = Node(nil, nil, nil, 7.84, 54.34)
g = node.point
node.shape(g, :type => 'Pharmacy', :name => 'Hyde Park Pharmacy')

179
180
181
182
183
184
185
# File 'lib/rosemary/element.rb', line 179

def shape(geom, attributes)
  fields = Hash.new
  attributes.each do |key, value|
    fields[key.to_s] = value
  end
  GeoRuby::Shp4r::ShpRecord.new(geom, fields)
end

#update_attributes(attribute_hash) ⇒ Object


142
143
144
145
146
147
148
149
150
151
# File 'lib/rosemary/element.rb', line 142

def update_attributes(attribute_hash)
  dirty = false
  attribute_hash.each do |key,value|
    if self.send(key).to_s != value.to_s
      self.send("#{key}=", value.to_s)
      dirty = true
    end
  end
  dirty
end