Skip to content
This repository has been archived by the owner on Nov 9, 2019. It is now read-only.

Commit

Permalink
Add documentation and rake generator task using yard.
Browse files Browse the repository at this point in the history
  • Loading branch information
christoph-buente committed Jun 2, 2012
1 parent 4deb6b5 commit 1cf825b
Show file tree
Hide file tree
Showing 18 changed files with 167 additions and 58 deletions.
6 changes: 6 additions & 0 deletions Rakefile
Expand Up @@ -19,5 +19,11 @@ task :c => :console

task :default => :spec

require 'yard'
YARD::Rake::YardocTask.new do |t|
t.files = ['lib/**/*.rb'] # optional
# t.options = ['--any', '--extra', '--opts'] # optional
end

require "bundler/gem_tasks"

3 changes: 3 additions & 0 deletions lib/hash.rb
@@ -1,12 +1,15 @@
# Standard ruby hash class extended with some additional behaviour.
class Hash

# symbolize_keys
define_method(:symbolize_keys!) do
self.each do |k,v|
self[k.to_sym] = v
self.delete(k)
end
end unless method_defined? :symbolize_keys!

# stringify_keys
define_method(:stringify_keys!) do
temp_hash = {}
self.each do |k,v|
Expand Down
1 change: 1 addition & 0 deletions lib/rosemary.rb
Expand Up @@ -12,6 +12,7 @@
require 'rosemary/user'
require 'rosemary/permissions'
require 'rosemary/errors'
require 'rosemary/client'
require 'rosemary/basic_auth_client'
require 'rosemary/oauth_client'
require 'rosemary/parser'
Expand Down
69 changes: 53 additions & 16 deletions lib/rosemary/api.rb
Expand Up @@ -9,38 +9,51 @@ module Rosemary
# api = Rosemary::Api.new(auth_client)
# @node = api.find_node(1234)
# @node.tags << {:wheelchair => 'no'}
# api.save(@node)
# @changeset = api.create_changeset('Set the wheelchair tag')
# api.save(@node, @changeset)
class Api
# Provide basic HTTP client behaviour.
include HTTParty

# The OSM API version supported by this gem.
API_VERSION = "0.6".freeze

# the default base URI for the API
base_uri "http://www.openstreetmap.org"
#base_uri "http://api06.dev.openstreetmap.org/api/#{API_VERSION}"

# Make sure the request don't run forever
default_timeout 5

# Use a custom parser to handle the OSM XML format.
parser Parser


# @return [Rosemary::Client] the client to be used to authenticate the user towards the OSM API.
attr_accessor :client

# @return [Rosemary::Changeset] the current changeset to be used for all writing acces.
attr_accessor :changeset

# Creates an Rosemary::Api object with an optional client
# @param [Rosemary::Client] client the client to authenticate the user for write access.
def initialize(client=nil)
@client = client
end

# Get a Node with specified ID from API.
#
# call-seq: find_node(id) -> Rosemary::Node
#
# @param [Fixnum] id the id of the node to find.
# @return [Rosemary::Node] the node with the given id.
# @raise [Rosemary::Gone] in case the node has been deleted.
def find_node(id)
find_element('node', id)
end

# Get a Way with specified ID from API.
#
# call-seq: find_way(id) -> Rosemary::Way
# @param [Fixnum] id the id of the node to find.
# @return [Rosemary::Way] the way with the given id.
#
def find_way(id)
find_element('way', id)
Expand All @@ -54,14 +67,6 @@ def find_relation(id)
find_element('relation', id)
end

# Get a Changeset with specified ID from API.
#
# call-seq: find_changeset(id) -> Rosemary::Changeset
#
def find_changeset(id)
find_element('changeset', id)
end

# Get a Changeset with specified ID from API
# if that changeset is missing, id is nil, or the changeset is closed
# create a new one
Expand All @@ -79,7 +84,7 @@ def find_open_changeset(id)

# Get the user which represented by the Rosemary::Client
#
# call-seq: find_user -> Rosemary::User
# @return: [Rosemary::User] user the user authenticated using the current client
#
def find_user
raise CredentialsMissing if client.nil?
Expand All @@ -96,15 +101,21 @@ def permissions
end
end

# Delete an element
# Deletes the given element using API write access.
#
# @param [Rosemary::Element] element the element to be created
# @param [Rosemary::Changeset] changeset the changeset to be used to wrap the write access.
# @return [Fixnum] the new version of the deleted element.
def destroy(element, changeset)
element.changeset = changeset.id
response = delete("/#{element.type.downcase}/#{element.id}", :body => element.to_xml) unless element.id.nil?
response.to_i # New version number
end

# Saves an element to the API.
# If it has no id yet, the element will be created, otherwise updated.
# Creates or updates an element depending on the current state of persistance.
#
# @param [Rosemary::Element] element the element to be created
# @param [Rosemary::Changeset] changeset the changeset to be used to wrap the write access.
def save(element, changeset)
response = if element.id.nil?
create(element, changeset)
Expand All @@ -113,23 +124,49 @@ def save(element, changeset)
end
end

# Create a new element using API write access.
#
# @param [Rosemary::Element] element the element to be created
# @param [Rosemary::Changeset] changeset the changeset to be used to wrap the write access.
# @return [Fixnum] the id of the newly created element.
def create(element, changeset)
element.changeset = changeset.id
put("/#{element.type.downcase}/create", :body => element.to_xml)
end

# Update an existing element using API write access.
#
# @param [Rosemary::Element] element the element to be created
# @param [Rosemary::Changeset] changeset the changeset to be used to wrap the write access.
# @return [Fixnum] the versiom of the updated element.
def update(element, changeset)
element.changeset = changeset.id
response = put("/#{element.type.downcase}/#{element.id}", :body => element.to_xml)
response.to_i # New Version number
end

# Create a new changeset with an optional comment
#
# @param [String] comment a meaningful comment for this changeset
# @return [Rosemary::Changeset] the changeset which was newly created
# @raise [Rosemary::NotFound] in case the changeset could not be found
def create_changeset(comment = nil)
changeset = Changeset.new(:tags => { :comment => comment })
changeset_id = put("/changeset/create", :body => changeset.to_xml).to_i
find_changeset(changeset_id) unless changeset_id == 0
end

# Get a Changeset with specified ID from API.
#
# @param [Integer] id the ID for the changeset you look for
# @return [Rosemary::Changeset] the changeset which was found with the id
def find_changeset(id)
find_element('changeset', id)
end

# Closes the given changeset.
#
# @param [Rosemary::Changeset] changeset the changeset to be closed
def close_changeset(changeset)
put("/changeset/#{changeset.id}/close")
end
Expand Down
13 changes: 11 additions & 2 deletions lib/rosemary/basic_auth_client.rb
@@ -1,15 +1,24 @@
class Rosemary::BasicAuthClient
attr_reader :username, :password
class Rosemary::BasicAuthClient < Rosemary::Client

# The username to be used to authenticate the user against the OMS API
attr_reader :username

# The password to be used to authenticate the user against the OMS API
attr_reader :password

def initialize(username, password)
@username = username
@password = password
end

# The username and password credentials as a Hash
# @return [Hash] the credential hash.
def credentials
{:username => username, :password => password}
end

# Override inspect message to keep the password from showing up
# in any logfile.
def inspect
"#<#{self.class.name}:#{self.object_id} @username='#{username}'>"
end
Expand Down
27 changes: 16 additions & 11 deletions lib/rosemary/changeset.rb
Expand Up @@ -3,30 +3,33 @@ module Rosemary
# Changeset is used in OpenStreetMap to bundle several changes into a kind of "commit"
class Changeset
# Unique ID
# @return [Fixnum]
attr_reader :id

# The user who last edited this object (as read from file, it
# is not updated by operations to this object)
# The user who last edited this object (as read from file, it is not updated by operations to this object)
# @return [Rosemary::User] the user who last edited this object
attr_accessor :user

# 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
# 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
# @return [Fixnum] the user id of the user who last edited this object
attr_accessor :uid

# True if this changeset is still open.
# @return [Boolean] is this changeset is still open.
attr_accessor :open

# Creation date of this changeset
# @return [Date] creation date of this changeset
attr_accessor :created_at

# When the changeset was closed
# @return [Date] when the changeset was closed
attr_accessor :closed_at

# Bounding box surrounding all changes made in this changeset
# @return [Float]
attr_accessor :min_lat, :min_lon, :max_lat, :max_lon

# Tags for this object
# @return [Hash]
attr_reader :tags

def initialize(attrs = {}) #:nodoc:
Expand Down Expand Up @@ -58,17 +61,17 @@ def open?
end

# List of attributes for a Changeset
# @return [Array]
def attribute_list
[:id, :user, :uid, :open, :created_at, :closed_at, :min_lat, :max_lat, :min_lon, :max_lon]
end

# Returns a hash of all non-nil attributes of this object.
#
# A hash of all non-nil attributes of this object.
# Keys of this hash are <tt>:id</tt>, <tt>:user</tt>,
# and <tt>:timestamp</tt>. For a Node also <tt>:lon</tt>
# and <tt>:lat</tt>.
#
# call-seq: attributes -> Hash
# @return [Hash] a hash of all non-nil attributes of this object.
#
def attributes
attrs = Hash.new
Expand All @@ -79,6 +82,8 @@ def attributes
attrs
end

# Renders the object as an xml representation compatible to the OSM API
# @return [String] XML
def to_xml(options = {})
xml = options[:builder] ||= Builder::XmlMarkup.new
xml.instruct! unless options[:skip_instruct]
Expand Down
3 changes: 3 additions & 0 deletions lib/rosemary/client.rb
@@ -0,0 +1,3 @@
# Superclass for all clients used to authenticate the user toward the OSM API.
class Rosemary::Client
end
11 changes: 9 additions & 2 deletions lib/rosemary/element.rb
Expand Up @@ -4,15 +4,18 @@ class Element
include ActiveModel::Validations

# Unique ID
# @return [Fixnum] id of this element
attr_reader :id

# The version of this object (as read from file, it
# is not updated by operations to this object)
# API 0.6 and above only
# @return [Fixnum] the current version
attr_accessor :version

# The user who last edited this object (as read from file, it
# The user who last edited this element (as read from file, it
# is not updated by operations to this object)
# @return [Rosemary::User] the user who last edititd this element
attr_accessor :user

# The user id of the user who last edited this object (as read from file, it
Expand All @@ -22,6 +25,7 @@ class Element

# Last change of this object (as read from file, it is not
# updated by operations to this object)
# @return [Time] last change of this object.
attr_reader :timestamp

# The changeset the last change of this object was made with.
Expand All @@ -31,6 +35,8 @@ class Element
attr_reader :tags

# Get Rosemary::Element from API
# @param [Fixnum] id the id of the element to load from the API

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)
Expand All @@ -56,6 +62,7 @@ def id=(id) # :nodoc:
end

# Set timestamp for this object.
# @param [Time] timestamp the time this object was created
def timestamp=(timestamp)
@timestamp = _check_timestamp(timestamp)
end
Expand Down Expand Up @@ -132,7 +139,7 @@ def update_attributes(attribute_hash)

# Has this object any tags?
#
# call-seq: is_tagged?
# @return [Boolean] has any tags?
#
def is_tagged?
! @tags.empty?
Expand Down
6 changes: 5 additions & 1 deletion lib/rosemary/errors.rb
Expand Up @@ -9,6 +9,7 @@ def initialize(data)
end
end

# This error occurs when the request send to the server could not be parsed.
class ParseError < StandardError; end

# This error occurs when Rosemary is instantiated without a client
Expand All @@ -24,6 +25,7 @@ class BadRequest < Error; end # 400
# password for a write operation.
class Unauthorized < Error; end # 401

# You don't have sufficient permissions to make that request.
class Forbidden < Error; end # 403

# The object was not found (HTTP 404). Generally means that the object doesn't exist
Expand All @@ -49,8 +51,10 @@ class Precondition < Error; end # 412
# Unspecified API server error.
class ServerError < Error; end # 500

# When the API service times out or returns an HTTP 503 status.
class Unavailable < Error; end # 503

class NotImplemented < Error; end # This method is not implemented yet.
# This method is not implemented yet.
class NotImplemented < Error; end

end
1 change: 1 addition & 0 deletions lib/rosemary/node.rb
Expand Up @@ -28,6 +28,7 @@ def initialize(attrs = {})
super(attrs)
end


def type
'Node'
end
Expand Down

0 comments on commit 1cf825b

Please sign in to comment.