koha 0.0.1

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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
@@ -0,0 +1,3 @@
1
+ ## v0.0.1
2
+
3
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in koha.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 fitz
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,84 @@
1
+ # Koha [![Build Status](https://travis-ci.org/cfitz/koha.png?branch=master)](https://travis-ci.org/cfitz/koha) [![Code Climate](https://codeclimate.com/github/cfitz/koha.png)](https://codeclimate.com/github/cfitz/koha)
2
+
3
+ A simple ruby wrapper for the Koha ILS RESTFUL API.
4
+
5
+ ### Prerequisites
6
+
7
+ You must install the RESTFUL api code to your instance of Koha. This project can be found here =>
8
+ http://git.biblibre.com/?p=koha-restful;a=summary
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'koha'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install koha
23
+
24
+ ## Usage
25
+
26
+ Here a quick irb walk-through...
27
+
28
+ > $ irb
29
+
30
+ > 1.9.3-p286 :001 > require 'koha'
31
+ => true
32
+
33
+ Make a Connection...
34
+
35
+ > 1.9.3-p286 :002 > k = Koha.connect({:url => "http://my.library.se/cgi-bin/koha/rest.pl"} )
36
+ > => #<Koha::Client:0x007fbcec9b6fd0 @uri=#<URI::HTTP:0x007fbcec9c3a00 URL:http://my.library.se/cgi-bin/koha/rest.pl/>, @proxy=nil, @connection=#<Koha::Connection:0x007fbcec9b6ff8>, @options={:url=>"http://my.library.se/cgi-bin/koha/rest.pl"}>
37
+
38
+ now get branch information...
39
+
40
+ > 1.9.3-p286 :003 > k.branches
41
+ > => [ { "name"=>"World Maritime University Library", "code"=>"WMU"}, { "name"=>"ebrary", "code"=>"EBR" } ]
42
+
43
+
44
+ find a bibliographic record
45
+ > 1.9.3-p286 :006 > k.find_biblio("17454")
46
+ > => [{"withdrawn"=>"1", "biblioitemnumber"=>"17454", .......
47
+
48
+ check is an biblio is holdable.....
49
+ > 1.9.3-p286 :009 > k.biblio_holdable?("17454" )
50
+ > => false
51
+
52
+ ... for a specific user ...
53
+ > 1.9.3-p286 :011 > k.biblio_holdable?("17454", :borrowernumber => "544" )
54
+ > => true
55
+
56
+
57
+ ... by user name ...
58
+ > 1.9.3-p286 :012 > k.biblio_holdable?("17454", :borrowername => "cf" )
59
+ > => true
60
+
61
+ get the user's holds.
62
+ > 1.9.3-p286 :013 > k.user_holds :borrowername => "cf"
63
+ > => [{"itemnumber"=>nil, "branchname"=>"World Maritime University Library", "itemcallnumber"=>nil, "hold_id"=>nil, "reservedate"=>"2013-02-20", "barcode"=>nil, "found"=>nil, "biblionumber"=>"76356", "cancellationdate"=>nil, "title"=>"Asian approaches to international law and the legacy of colonialism and imperialism :", "rank"=>"1", "branchcode"=>"WMU"}]
64
+
65
+ or get the user's issues
66
+
67
+ > 1.9.3-p286 :014 > k.user_issues :borrowernumber => "544"
68
+ > => [{"itemnumber"=>"42414", "itemcallnumber"=>"KD1819 .H54 2003", "barcode"=>"022593", "date_due"=>"2013-03-11T23:59:00", "renewable"=>true, "issuedate"=>"2012-11-21T00:00:00", "biblionumber"=>"17454", "title"=>"Maritime law", "borrowernumber"=>"544", "branchcode"=>"WMU"}]
69
+
70
+
71
+
72
+ ### Development
73
+
74
+ Checkout the code. rake will run the tests. rake coverage will generate coverage. rake yard will generate documentation.
75
+
76
+
77
+ ## Contributing
78
+
79
+ 1. Fork it
80
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
81
+ 2.5 Write the code and add tests.
82
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
83
+ 4. Push to the branch (`git push origin my-new-feature`)
84
+ 5. Create new Pull Request
@@ -0,0 +1,21 @@
1
+ require 'rake'
2
+ require 'bundler/gem_tasks'
3
+
4
+ require 'rubygems/package_task'
5
+
6
+ task :environment do
7
+ require File.dirname(__FILE__) + '/lib/koha_client'
8
+ end
9
+
10
+ Dir['tasks/**/*.rake'].each { |t| load t }
11
+
12
+ task :default => ['spec:api']
13
+
14
+
15
+
16
+ task :coverage do
17
+ # add simplecov
18
+ ENV["COVERAGE"] = 'yes'
19
+ # run the specs
20
+ Rake::Task['spec:api'].execute
21
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ require "koha"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "koha"
8
+ s.summary = "A Ruby client for Koha ILSDI interface"
9
+ s.description = %q{Easy interface for the Koha ILSDI API (https://github.com/Koha-Community/Koha/blob/master/C4/ILSDI/Services.pm) }
10
+ s.version = Koha.version
11
+ s.authors = ["chris fitzpatrick"]
12
+ s.email = ["chrisfitzpat@gmail.com"]
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = ["lib"]
17
+
18
+ s.add_development_dependency 'simplecov', '0.7.1'
19
+ s.add_development_dependency 'yard', '~> 0.8.4.1'
20
+ s.add_development_dependency 'webmock', '~> 1.9.3'
21
+ s.add_development_dependency 'rake', '~> 10.0.3'
22
+ s.add_development_dependency 'rdoc', '~> 3.9.5'
23
+ s.add_development_dependency 'rspec', '~> 2.6.0'
24
+ s.add_development_dependency 'redcarpet'
25
+ end
@@ -0,0 +1,20 @@
1
+ $: << "#{File.dirname(__FILE__)}" unless $:.include? File.dirname(__FILE__)
2
+
3
+ require 'rubygems'
4
+
5
+ module Koha
6
+
7
+ %W(Client Error Connection Uri Version).each{|n| autoload n.to_sym, "koha/#{n.downcase}"}
8
+
9
+ def self.version; "0.0.1" end
10
+
11
+ VERSION = self.version
12
+
13
+ def self.connect *args
14
+ driver = Class === args[0] ? args[0] : Koha::Connection
15
+ opts = Hash === args[-1] ? args[-1] : {}
16
+ Client.new driver.new, opts
17
+ end
18
+
19
+
20
+ end
@@ -0,0 +1,210 @@
1
+ require 'json'
2
+
3
+ class Koha::Client
4
+
5
+ attr_reader :connection, :uri, :proxy, :options
6
+
7
+ def initialize connection, options = {}
8
+ @proxy = @uri = nil
9
+ @connection = connection
10
+ unless false === options[:url]
11
+ url = options[:url] ? options[:url].dup : 'http://localhost/cgi-bin/koha/rest.pl/'
12
+ url << "/" unless url[-1] == ?/
13
+ @uri = Koha::Uri.create url
14
+ if options[:proxy]
15
+ proxy_url = options[:proxy].dup
16
+ proxy_url << "/" unless proxy_url.nil? or proxy_url[-1] == ?/
17
+ @proxy = Koha::Uri.create proxy_url if proxy_url
18
+ end
19
+ end
20
+ @options = options
21
+ end
22
+
23
+ # returns the uri proxy if present,
24
+ # otherwise just the uri object.
25
+ def base_uri
26
+ @proxy ? @proxy : @uri
27
+ end
28
+
29
+ # Create the get, post, and head methods
30
+ %W(get post put).each do |meth|
31
+ class_eval <<-RUBY
32
+ def #{meth} path, opts = {}, &block
33
+ send_and_receive path, opts.merge(:method => :#{meth}), &block
34
+ end
35
+ RUBY
36
+ end
37
+
38
+
39
+ # +send_and_receive+ is the main request method responsible for sending requests to the +connection+ object.
40
+ #
41
+ # "path" : A string value that directs the client to the API REST method
42
+ # "opts" : A hash, which can contain the following keys:
43
+ # :method : optional - the http method (:get, :post or :put)
44
+ # :params : optional - the query string params in hash form
45
+ # All other options are passed right along to the connection's +send_and_receive+ method (:get, :post, or :put)
46
+ #
47
+ #
48
+ # creates a request context hash,
49
+ # sends it to the connection's +execute+ method
50
+ # which returns a simple hash,
51
+ # then passes the request/response into +adapt_response+.
52
+ def send_and_receive path, opts
53
+ request_context = build_request path, opts
54
+ [:open_timeout, :read_timeout].each do |k|
55
+ request_context[k] = @options[k]
56
+ end
57
+ execute request_context
58
+ end
59
+
60
+ # send a request to the connection to be submitted
61
+ def execute request_context
62
+ raw_response = connection.execute self, request_context
63
+ adapt_response(request_context, raw_response) unless raw_response.nil?
64
+ end
65
+
66
+ # +build_request+ accepts a path and options hash,
67
+ # then prepares a normalized hash to return for sending
68
+ # +build_request+ sets up the uri/query string
69
+ # and converts the +data+ arg to form-urlencoded,
70
+ # returns a hash with the following keys:
71
+ # :method
72
+ # :params
73
+ # :uri
74
+ # :path
75
+ # :query
76
+
77
+ def build_request path, opts
78
+ raise "path must be a string or symbol, not #{path.inspect}" unless [String,Symbol].include?(path.class)
79
+ path = path.to_s
80
+ opts[:proxy] = proxy unless proxy.nil?
81
+ opts[:method] ||= :get
82
+ opts[:params] ||= {}
83
+ opts[:params][:borrowernumber] = opts[:borrowernumber] if opts[:borrowernumber]
84
+ opts[:params][:user_name] = opts[:borrowername] if opts[:borrowername]
85
+ query = Koha::Uri.to_params(opts[:params]) unless opts[:params].empty?
86
+ opts[:query] = query
87
+ opts[:path] = path
88
+ if base_uri
89
+ opts[:uri] = URI.join(base_uri, path.to_s)
90
+ opts[:uri].merge!("?#{query}" ) if query
91
+ end
92
+ opts
93
+ end
94
+
95
+
96
+ # A mixin for used by #adapt_response
97
+ module Context
98
+ attr_accessor :request, :response
99
+ end
100
+
101
+ # This method will evaluate the :body value
102
+ # if the request has an :evaulte value, the response is send to
103
+ # the evaluate_json_response, which returns just the node.
104
+ # this is a convience to simply return "false" or "true" and not a bunch of stupid
105
+ # json that has nothing that makes any god-damn sense.
106
+ # ... otherwise, the json is simply returned.
107
+ def adapt_response request, response
108
+ raise "The response does not have the correct keys => :body, :headers, :status" unless
109
+ %W(body headers status) == response.keys.map{|k|k.to_s}.sort
110
+ raise Koha::Error::Http.new request, response unless [200,302].include? response[:status]
111
+ result = request[:evaluate] ? evaluate_json_response(request, response, request[:evaluate]) : response[:body]
112
+ result.extend Context
113
+ result.request, result.response = request, response
114
+ result
115
+ end
116
+
117
+
118
+
119
+ ##### KOHA REST API METHODS #######
120
+
121
+ ### Info Methods ###
122
+
123
+ # returns a hash of [ { :code => "1", :name => "Our Branch Name "}]
124
+ def branches opts= {}
125
+ JSON.parse(get "branches", opts)
126
+ end
127
+
128
+
129
+ ### USER Methods ###
130
+
131
+ # returns a hash of all the users
132
+ def all_users opts= {}
133
+ JSON.parse(get "user/all", opts )
134
+ end
135
+
136
+ # returns a hash of patrons enrolled today
137
+ def today_users opts= {}
138
+ JSON.parse(get "user/today", opts)
139
+ end
140
+
141
+
142
+ def user_holds opts= {}
143
+ path, opts = build_user_path("holds", opts)
144
+ JSON.parse(get path, opts)
145
+ end
146
+
147
+ def user_issues opts= {}
148
+ path, opts = build_user_path("issues", opts)
149
+ JSON.parse(get path, opts)
150
+ end
151
+
152
+ def build_user_path rest_method, opts= {}
153
+ raise ArgumentError unless ( opts[:borrowernumber] or opts[:borrowername] ) #we have to be passed either a name or number
154
+ borrowernumber, borrowername = opts.delete(:borrowernumber), opts.delete(:borrowername)
155
+ path = borrowernumber ? "user/byid/#{borrowernumber}/#{rest_method}" : "user/#{borrowername}/#{rest_method}"
156
+ return path, opts
157
+ end
158
+
159
+
160
+ ### Biblio and Item Methods ###
161
+
162
+ # This method will get the item record from koha given the biblionumber
163
+ def find_biblio biblionumber, opts = {}
164
+ biblionumber = biblionumber.to_s
165
+ JSON.parse(get "biblio/#{biblionumber}/items", opts)
166
+ end
167
+
168
+ # wrapper to check if a biblio is holdable
169
+ # take a koha biblio number and standard client opts
170
+ def biblio_holdable?(biblionumber, opts = {})
171
+ is_holdable?(:biblio, biblionumber, opts )
172
+ end
173
+
174
+ # wrapper to check a biblio items holdabale statues.
175
+ # takes a koha bilionumber and standard client opts
176
+ # this returns just a hash of the items and their status, no need to evaulate.
177
+ def biblio_items_holdable?(biblionumber, opts = {} )
178
+ opts ||= {}
179
+ opts[:holdable] = "items_holdable_status"
180
+ opts[:evaluate] ||= false
181
+ is_holdable?(:biblio, biblionumber, opts)
182
+ end
183
+
184
+ # wrapper to check is an item is holdable
185
+ def item_holdable?(itemnumber, opts = {})
186
+ is_holdable?(:item, itemnumber, opts)
187
+ end
188
+
189
+ def is_holdable?(koha_type, identifier, opts = {} )
190
+ opts ||= {}
191
+ opts[:evaluate] = :is_holdable unless opts[:evaluate] == false
192
+ holdable = opts[:holdable] ? opts[:holdable] : "holdable"
193
+ koha_type = koha_type.to_s == "item" ? "item" : "biblio"
194
+ identifier = identifier.to_s
195
+ get "#{koha_type}/#{identifier}/#{holdable}", opts
196
+ end
197
+
198
+ protected
199
+
200
+ # this is used to retrun a ruby primitive based on a json node. For example holdable returns { "is_holdable" : true, "reasons" : [] }
201
+ # and we just want true.
202
+ def evaluate_json_response request, response, node
203
+ json = JSON.parse(response[:body])
204
+ json[node.to_s]
205
+ end
206
+
207
+
208
+
209
+
210
+ end
@@ -0,0 +1,70 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+
4
+
5
+ # taken from RSOLR's http client
6
+ class Koha::Connection
7
+
8
+ def execute client, request_context
9
+ h = http request_context[:uri], request_context[:proxy], request_context[:read_timeout], request_context[:open_timeout]
10
+ request = setup_raw_request request_context
11
+ request.body = request_context[:data] if request_context[:method] == :post and request_context[:data]
12
+ begin
13
+ response = h.request request
14
+ charset = response.type_params["charset"]
15
+ {:status => response.code.to_i, :headers => response.to_hash, :body => force_charset(response.body, charset)}
16
+ rescue Errno::ECONNREFUSED => e
17
+ raise(Errno::ECONNREFUSED.new(request_context.inspect))
18
+ # catch the undefined closed? exception -- this is a confirmed ruby bug
19
+ rescue NoMethodError
20
+ $!.message == "undefined method `closed?' for nil:NilClass" ?
21
+ raise(Errno::ECONNREFUSED.new) :
22
+ raise($!)
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ # This returns a singleton of a Net::HTTP or Net::HTTP.Proxy request object.
29
+ def http uri, proxy = nil, read_timeout = nil, open_timeout = nil
30
+ @http ||= (
31
+ http = if proxy
32
+ proxy_user, proxy_pass = proxy.userinfo.split(/:/) if proxy.userinfo
33
+ Net::HTTP.Proxy(proxy.host, proxy.port, proxy_user, proxy_pass).new uri.host, uri.port
34
+ else
35
+ Net::HTTP.new uri.host, uri.port
36
+ end
37
+ http.use_ssl = uri.port == 443 || uri.instance_of?(URI::HTTPS)
38
+ http.read_timeout = read_timeout if read_timeout
39
+ http.open_timeout = open_timeout if open_timeout
40
+ http
41
+ )
42
+ end
43
+
44
+ #
45
+ def setup_raw_request request_context
46
+ http_method = case request_context[:method]
47
+ when :get
48
+ Net::HTTP::Get
49
+ when :post
50
+ Net::HTTP::Post
51
+ when :put
52
+ Net::HTTP::Put
53
+ else
54
+ raise "Only :get, :post and :head http method types are allowed."
55
+ end
56
+ headers = request_context[:headers] || {}
57
+ raw_request = http_method.new request_context[:uri].request_uri
58
+ raw_request.initialize_http_header headers
59
+ raw_request.basic_auth(request_context[:uri].user, request_context[:uri].password) if request_context[:uri].user && request_context[:uri].password
60
+ raw_request
61
+ end
62
+
63
+ private
64
+
65
+ def force_charset body, charset
66
+ return body unless charset and body.respond_to?(:force_encoding)
67
+ body.force_encoding(charset)
68
+ end
69
+
70
+ end
@@ -0,0 +1,75 @@
1
+ module Koha::Error
2
+
3
+
4
+
5
+ class Http < RuntimeError
6
+
7
+
8
+ # ripped right from ActionPack
9
+ # Defines the standard HTTP status codes, by integer, with their
10
+ # corresponding default message texts.
11
+ # Source: http://www.iana.org/assignments/http-status-codes
12
+ STATUS_CODES = {
13
+ 100 => "Continue",
14
+ 101 => "Switching Protocols",
15
+ 102 => "Processing",
16
+
17
+ 200 => "OK",
18
+ 201 => "Created",
19
+ 202 => "Accepted",
20
+ 203 => "Non-Authoritative Information",
21
+ 204 => "No Content",
22
+ 205 => "Reset Content",
23
+ 206 => "Partial Content",
24
+ 207 => "Multi-Status",
25
+ 226 => "IM Used",
26
+
27
+ 300 => "Multiple Choices",
28
+ 301 => "Moved Permanently",
29
+ 302 => "Found",
30
+ 303 => "See Other",
31
+ 304 => "Not Modified",
32
+ 305 => "Use Proxy",
33
+ 307 => "Temporary Redirect",
34
+
35
+ 400 => "Bad Request",
36
+ 401 => "Unauthorized",
37
+ 402 => "Payment Required",
38
+ 403 => "Forbidden",
39
+ 404 => "Not Found",
40
+ 405 => "Method Not Allowed",
41
+ 406 => "Not Acceptable",
42
+ 407 => "Proxy Authentication Required",
43
+ 408 => "Request Timeout",
44
+ 409 => "Conflict",
45
+ 410 => "Gone",
46
+ 411 => "Length Required",
47
+ 412 => "Precondition Failed",
48
+ 413 => "Request Entity Too Large",
49
+ 414 => "Request-URI Too Long",
50
+ 415 => "Unsupported Media Type",
51
+ 416 => "Requested Range Not Satisfiable",
52
+ 417 => "Expectation Failed",
53
+ 422 => "Unprocessable Entity",
54
+ 423 => "Locked",
55
+ 424 => "Failed Dependency",
56
+ 426 => "Upgrade Required",
57
+
58
+ 500 => "Internal Server Error",
59
+ 501 => "Not Implemented",
60
+ 502 => "Bad Gateway",
61
+ 503 => "Service Unavailable",
62
+ 504 => "Gateway Timeout",
63
+ 505 => "HTTP Version Not Supported",
64
+ 507 => "Insufficient Storage",
65
+ 510 => "Not Extended"
66
+ }
67
+
68
+ def initialize request, response
69
+ @request, @response = request, response
70
+ end
71
+
72
+ end
73
+
74
+
75
+ end
@@ -0,0 +1,59 @@
1
+ require 'uri'
2
+
3
+ module Koha::Uri
4
+
5
+ def create url
6
+ ::URI.parse url[-1] == ?/ ? url : "#{url}/"
7
+ end
8
+
9
+ # Returns a query string param pair as a string.
10
+ # Both key and value are escaped.
11
+ def build_param(k,v, escape = true)
12
+ escape ?
13
+ "#{escape_query_value(k)}=#{escape_query_value(v)}" :
14
+ "#{k}=#{v}"
15
+ end
16
+
17
+ # Return the bytesize of String; uses String#size under Ruby 1.8 and
18
+ # String#bytesize under 1.9.
19
+ if ''.respond_to?(:bytesize)
20
+ def bytesize(string)
21
+ string.bytesize
22
+ end
23
+ else
24
+ def bytesize(string)
25
+ string.size
26
+ end
27
+ end
28
+
29
+ # Creates a ILSDI based query string.
30
+ # Keys that have arrays values are set multiple times:
31
+ # params_to_solr(:service => 'foo', :biblionumbers => ['1', '2'])
32
+ # is converted to:
33
+ # ?service=foo&biblinumbers=1+2
34
+ def to_params(params, escape = true)
35
+ mapped = params.map do |k, v|
36
+ next if v.to_s.empty?
37
+ if v.class == Array
38
+ build_param k, v.join("+"), false
39
+ else
40
+ build_param k, v, escape
41
+ end
42
+ end
43
+ mapped.compact.join("&")
44
+ end
45
+
46
+
47
+ # Performs URI escaping so that you can construct proper
48
+ # query strings faster. Use this rather than the cgi.rb
49
+ # version since it's faster.
50
+ # (Stolen from Rack).
51
+ def escape_query_value(s)
52
+ s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/u) {
53
+ '%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
54
+ }.tr(' ', '+')
55
+ end
56
+
57
+ extend self
58
+
59
+ end
@@ -0,0 +1,6 @@
1
+ module Koha
2
+
3
+ VERSION = "0.0.1"
4
+
5
+
6
+ end
@@ -0,0 +1,172 @@
1
+ require 'spec_helper'
2
+ describe "Koha::Client" do
3
+
4
+ module ClientHelper
5
+ def client
6
+ @client ||= (
7
+ connection = Koha::Connection.new
8
+ Koha::Client.new connection, :url => "http://localhost/koha", :read_timeout => 42, :open_timeout=>43
9
+ )
10
+ end
11
+ end
12
+
13
+ context "initialize" do
14
+ it "should accept whatevs and set it as the @connection" do
15
+ Koha::Client.new(:whatevs).connection.should == :whatevs
16
+ end
17
+
18
+
19
+ end
20
+
21
+ context "send_and_receive" do
22
+ include ClientHelper
23
+ it "should forward these method calls the #connection object" do
24
+ [:get, :post, :put].each do |meth|
25
+ client.connection.should_receive(:execute).
26
+ and_return({:status => 200, :body => "{}", :headers => {}})
27
+ client.send_and_receive '', :method => meth, :params => {}, :data => nil, :headers => {}
28
+ end
29
+ end
30
+
31
+ it "should be timeout aware" do
32
+ [:get, :post, :put].each do |meth|
33
+ client.connection.should_receive(:execute).with(client, hash_including(:read_timeout => 42, :open_timeout=>43))
34
+ client.send_and_receive '', :method => meth, :params => {}, :data => nil, :headers => {}
35
+ end
36
+ end
37
+ end
38
+
39
+ context "post" do
40
+ include ClientHelper
41
+ it "should pass the expected params to the connection's #execute method" do
42
+ request_opts = {:data => "the data", :method=>:post, :headers => {"Content-Type" => "text/plain"}}
43
+ client.connection.should_receive(:execute).
44
+ with(client, hash_including(request_opts)).
45
+ and_return(
46
+ :body => "",
47
+ :status => 200,
48
+ :headers => {"Content-Type"=>"text/plain"}
49
+ )
50
+ client.post "biblio/update", request_opts
51
+ end
52
+ end
53
+
54
+
55
+
56
+ context "adapt_response" do
57
+ include ClientHelper
58
+
59
+
60
+ end
61
+
62
+ context "build_request" do
63
+ include ClientHelper
64
+ it 'should return a request context array' do
65
+ result = client.build_request('select',
66
+ :method => :get,
67
+ :params => {},
68
+ :borrowernumber => "512",
69
+ :borrowername => "cf"
70
+ )
71
+ [/user_name=cf/, /borrowernumber=512/].each do |pattern|
72
+ result[:query].should match pattern
73
+ end
74
+ end
75
+
76
+
77
+
78
+ # Check responses to see how the KOHA RESTFUL API v1.0 responds.
79
+ context "koha methods" do
80
+ include ClientHelper
81
+
82
+ # branches
83
+ it "should call the REST API branch method with #client" do
84
+ stub_request(:get, "http://localhost/koha/branches").to_return(:status => 200, :body =>
85
+ "[{\"name\":\"World Maritime University Library\",\"code\":\"WMU\"},{\"name\":\"ebrary\",\"code\":\"EBR\"}]",
86
+ :headers => {})
87
+ client.branches
88
+ WebMock.should have_requested(:get, "http://localhost/koha/branches")
89
+ end
90
+
91
+
92
+ # user
93
+ it "should call the user/all method for #all_users" do
94
+ stub_request(:get, "http://localhost/koha/user/all").to_return(:status => 200, :body =>
95
+ "[{\"categorycode\":\"T\",\"B_address\":\"\",\"contactnote\":\"\",\"ethnicity\":null,\"email\":\"foo@wmu.se\",\"password\":\"1+1898juif\",\"B_country\":\"\",\"borrowernumber\":\"5\",\"lost\":\"0\",\"branchcode\":\"WMU\",\"streettype\":null,\"altcontactaddress3\":\"\",\"contactfirstname\":null,\"title\":\"\",\"attributes\":[],\"ethnotes\":null,\"relationship\":null,\"mobile\":\"\",\"fax\":\"\",\"altcontactphone\":\"\",\"contactname\":\"WMU\",\"country\":\"Sweden\",\"dateenrolled\":\"2010-02-03\",\"altcontactstate\":null,\"guarantorid\":\"0\",\"address2\":\"\",\"borrowernotes\":\"\",\"dateexpiry\":\"2018-05-03\",\"sort2\":\"\",\"contacttitle\":null,\"phonepro\":\"+46-40-35 63 90\",\"smsalertnumber\":null,\"B_streetnumber\":null,\"emailpro\":\"mbf@wmu.se\",\"firstname\":\"Michael\",\"altcontactcountry\":\"\",\"gonenoaddress\":\"0\",\"othernames\":\"\",\"state\":null,\"dateofbirth\":null,\"altcontactaddress2\":\"\",\"B_streettype\":null,\"debarred\":null,\"B_state\":null,\"address\":\"PO Box 500\",\"B_address2\":\"\",\"privacy\":\"1\",\"streetnumber\":\"\",\"surname\":\"BALDAUF\",\"cardnumber\":\"MBF\",\"altcontactsurname\":\"\",\"altcontactzipcode\":\"\",\"opacnote\":\"\",\"altcontactfirstname\":\"\",\"userid\":\"mbf\",\"B_zipcode\":\"\",\"B_email\":\"\",\"city\":\"Malm\",\"B_phone\":\"\",\"debarredcomment\":null,\"initials\":\"MB\",\"sort1\":\"\",\"flags\":null,\"zipcode\":\"20124\",\"phone\":\"\",\"sex\":\"M\",\"altcontactaddress1\":\"\",\"B_city\":\"\"}]"
96
+ )
97
+ client.all_users
98
+ WebMock.should have_requested(:get, "http://localhost/koha/user/all")
99
+ end
100
+
101
+
102
+ it "should call the user/all method for #all_users" do
103
+ stub_request(:get, "http://localhost/koha/user/today").to_return(:status => 200, :body =>
104
+ "[{\"categorycode\":\"T\",\"B_address\":\"\",\"contactnote\":\"\",\"ethnicity\":null,\"email\":\"foo@wmu.se\",\"password\":\"1+1898juif\",\"B_country\":\"\",\"borrowernumber\":\"5\",\"lost\":\"0\",\"branchcode\":\"WMU\",\"streettype\":null,\"altcontactaddress3\":\"\",\"contactfirstname\":null,\"title\":\"\",\"attributes\":[],\"ethnotes\":null,\"relationship\":null,\"mobile\":\"\",\"fax\":\"\",\"altcontactphone\":\"\",\"contactname\":\"WMU\",\"country\":\"Sweden\",\"dateenrolled\":\"2010-02-03\",\"altcontactstate\":null,\"guarantorid\":\"0\",\"address2\":\"\",\"borrowernotes\":\"\",\"dateexpiry\":\"2018-05-03\",\"sort2\":\"\",\"contacttitle\":null,\"phonepro\":\"+46-40-35 63 90\",\"smsalertnumber\":null,\"B_streetnumber\":null,\"emailpro\":\"mbf@wmu.se\",\"firstname\":\"Michael\",\"altcontactcountry\":\"\",\"gonenoaddress\":\"0\",\"othernames\":\"\",\"state\":null,\"dateofbirth\":null,\"altcontactaddress2\":\"\",\"B_streettype\":null,\"debarred\":null,\"B_state\":null,\"address\":\"PO Box 500\",\"B_address2\":\"\",\"privacy\":\"1\",\"streetnumber\":\"\",\"surname\":\"BALDAUF\",\"cardnumber\":\"MBF\",\"altcontactsurname\":\"\",\"altcontactzipcode\":\"\",\"opacnote\":\"\",\"altcontactfirstname\":\"\",\"userid\":\"mbf\",\"B_zipcode\":\"\",\"B_email\":\"\",\"city\":\"Malm\",\"B_phone\":\"\",\"debarredcomment\":null,\"initials\":\"MB\",\"sort1\":\"\",\"flags\":null,\"zipcode\":\"20124\",\"phone\":\"\",\"sex\":\"M\",\"altcontactaddress1\":\"\",\"B_city\":\"\"}]"
105
+ )
106
+ client.today_users
107
+ WebMock.should have_requested(:get, "http://localhost/koha/user/today")
108
+ end
109
+
110
+ it "should call the user holds method for #user_holds" do
111
+ stub_request(:get, "http://localhost/koha/user/byid/1/holds").to_return(:status => 200, :body =>
112
+ "[{\"itemnumber\":null,\"branchname\":\"World Maritime University Library\",\"itemcallnumber\":null,\"hold_id\":null,\"reservedate\":\"2013-02-20\",\"barcode\":null,\"found\":null,\"biblionumber\":\"76356\",\"cancellationdate\":null,\"title\":\"Asian approaches to international law and the legacy of colonialism and imperialism :\",\"rank\":\"1\",\"branchcode\":\"WMU\"}]" )
113
+ client.user_holds(:borrowernumber => "1")
114
+ WebMock.should have_requested(:get, "http://localhost/koha/user/byid/1/holds")
115
+ end
116
+
117
+
118
+ it "should call the user issues method for #user_issues" do
119
+ stub_request(:get, "http://localhost/koha/user/cf/issues").to_return(:status => 200, :body =>
120
+ "[{\"itemnumber\":\"42414\",\"itemcallnumber\":\"KD1819 .H54 2003\",\"barcode\":\"022593\",\"date_due\":\"2013-03-11T23:59:00\",\"renewable\":true,\"issuedate\":\"2012-11-21T00:00:00\",\"biblionumber\":\"17454\",\"title\":\"Maritime law\",\"borrowernumber\":\"544\",\"branchcode\":\"WMU\"}]" )
121
+ client.user_issues(:borrowername => "cf")
122
+ WebMock.should have_requested(:get, "http://localhost/koha/user/cf/issues")
123
+ end
124
+
125
+
126
+ # biblio and items
127
+
128
+ it "should call the biblio items method for #find_biblio" do
129
+ stub_request(:get, "http://localhost/koha/biblio/1/items").to_return(:status => 200, :body =>
130
+ "[{\"withdrawn\":\"0\",\"biblioitemnumber\":\"1\",\"restricted\":null,\"wthdrawn\":\"0\",\"holdingbranchname\":\"World Maritime University Library\",\"notforloan\":\"0\",\"replacementpricedate\":\"2010-02-05\",\"itemnumber\":\"1\",\"ccode\":null,\"itemnotes\":null,\"location\":\"GEN\",\"itemcallnumber\":\"HD30.3 .A32 1989\",\"stack\":null,\"date_due\":\"\",\"barcode\":\"011376\",\"itemlost\":\"0\",\"uri\":null,\"materials\":null,\"datelastseen\":\"2010-02-05\",\"price\":null,\"issues\":null,\"homebranch\":\"WMU\",\"replacementprice\":null,\"more_subfields_xml\":null,\"cn_source\":\"lcc\",\"homebranchname\":\"World Maritime University Library\",\"booksellerid\":null,\"biblionumber\":\"1\",\"renewals\":null,\"holdingbranch\":\"WMU\",\"timestamp\":\"2012-11-28 07:47:23\",\"damaged\":\"0\",\"stocknumber\":null,\"cn_sort\":\"HD_00030_3_A32_1989\",\"reserves\":null,\"dateaccessioned\":\"2010-02-05\",\"datelastborrowed\":null,\"enumchron\":null,\"copynumber\":\"1\",\"permanent_location\":null,\"onloan\":null,\"paidfor\":null,\"itype\":\"BOOK\"}]" )
131
+ client.find_biblio("1")
132
+ WebMock.should have_requested(:get, "http://localhost/koha/biblio/1/items")
133
+ end
134
+
135
+
136
+ it "should call the biblio items method for #find_biblio" do
137
+ stub_request(:get, "http://localhost/koha/biblio/1/items").to_return(:status => 200, :body =>
138
+ "[{\"withdrawn\":\"0\",\"biblioitemnumber\":\"1\",\"restricted\":null,\"wthdrawn\":\"0\",\"holdingbranchname\":\"World Maritime University Library\",\"notforloan\":\"0\",\"replacementpricedate\":\"2010-02-05\",\"itemnumber\":\"1\",\"ccode\":null,\"itemnotes\":null,\"location\":\"GEN\",\"itemcallnumber\":\"HD30.3 .A32 1989\",\"stack\":null,\"date_due\":\"\",\"barcode\":\"011376\",\"itemlost\":\"0\",\"uri\":null,\"materials\":null,\"datelastseen\":\"2010-02-05\",\"price\":null,\"issues\":null,\"homebranch\":\"WMU\",\"replacementprice\":null,\"more_subfields_xml\":null,\"cn_source\":\"lcc\",\"homebranchname\":\"World Maritime University Library\",\"booksellerid\":null,\"biblionumber\":\"1\",\"renewals\":null,\"holdingbranch\":\"WMU\",\"timestamp\":\"2012-11-28 07:47:23\",\"damaged\":\"0\",\"stocknumber\":null,\"cn_sort\":\"HD_00030_3_A32_1989\",\"reserves\":null,\"dateaccessioned\":\"2010-02-05\",\"datelastborrowed\":null,\"enumchron\":null,\"copynumber\":\"1\",\"permanent_location\":null,\"onloan\":null,\"paidfor\":null,\"itype\":\"BOOK\"}]" )
139
+ client.find_biblio("1")
140
+ WebMock.should have_requested(:get, "http://localhost/koha/biblio/1/items")
141
+ end
142
+
143
+ it "should call the biblio holdable for #biblio_holdable?" do
144
+ stub_request(:get, "http://localhost/koha/biblio/1/holdable").to_return(:status => 200, :body =>
145
+ "{\"is_holdable\":true,\"reasons\":[]}" )
146
+ client.biblio_holdable?("1").should be_true
147
+ WebMock.should have_requested(:get, "http://localhost/koha/biblio/1/holdable")
148
+ end
149
+
150
+ # show how to use a borrowername
151
+ it "should call the biblio holdable items for #biblio_items_holdable?" do
152
+ stub_request(:get, "http://localhost/koha/biblio/1/items_holdable_status?user_name=cf").to_return(:status => 200, :body =>
153
+ "{\"is_holdable\":true,\"reasons\":[]}" )
154
+ client.biblio_items_holdable?("1", :borrowername => "cf" ).should be_true
155
+ WebMock.should have_requested(:get, "http://localhost/koha/biblio/1/items_holdable_status?user_name=cf")
156
+ end
157
+
158
+ # show how to use a borrowernumber
159
+ it "should call the items holdable API method for #item_holdable?" do
160
+ stub_request(:get, "http://localhost/koha/item/74297/holdable?user_name=cf").to_return(:status => 200, :body =>
161
+ "{\"is_holdable\":false,\"reasons\":[]}" )
162
+ client.item_holdable?("74297", :borrowername => "cf" ).should be_false
163
+ WebMock.should have_requested(:get, "http://localhost/koha/item/74297/holdable?user_name=cf")
164
+ end
165
+
166
+
167
+
168
+ end
169
+
170
+
171
+ end
172
+ end
@@ -0,0 +1,152 @@
1
+ require 'spec_helper'
2
+ require 'base64'
3
+
4
+ describe "Koha::Connection" do
5
+
6
+ context "setup_raw_request" do
7
+
8
+ before(:each) do
9
+ @c = Koha::Connection.new
10
+ @base_url = "http://localhost:8983/koha/rest.pl"
11
+ @client = Koha::Client.new @c, :url => @base_url
12
+ end
13
+
14
+ it "should set up a get request" do
15
+ req = @c.send :setup_raw_request, {:headers => {"content-type" => "application/json"}, :method => :get, :uri => URI.parse(@base_url + "/biblio/1/items?borrowername=cf")}
16
+ headers = {}
17
+ req.each_header{|k,v| headers[k] = v}
18
+ req.method.should == "GET"
19
+ headers.should == {"content-type"=>"application/json"}
20
+ end
21
+
22
+ it "should set up a post request" do
23
+ req = @c.send :setup_raw_request, {:headers => {"content-type" => "application/json"}, :method => :post, :uri => URI.parse(@base_url + "/biblio/1/items?borrowername=cf")}
24
+ headers = {}
25
+ req.each_header{|k,v| headers[k] = v}
26
+ req.method.should == "POST"
27
+ headers.should == {"content-type"=>"application/json"}
28
+ end
29
+
30
+ it "should set up a post request" do
31
+ req = @c.send :setup_raw_request, {:headers => {"content-type" => "application/json"}, :method => :put, :uri => URI.parse(@base_url + "/biblio/1/items?borrowername=cf")}
32
+ headers = {}
33
+ req.each_header{|k,v| headers[k] = v}
34
+ req.method.should == "PUT"
35
+ headers.should == {"content-type"=>"application/json"}
36
+ end
37
+
38
+ it "should raise error if something weird is set as method" do
39
+ expect { @c.send :setup_raw_request, {:headers => {"content-type" => "application/json"}, :method => :head, :uri => URI.parse(@base_url + "/biblio/1/items?borrowername=cf")} }.to raise_error("Only :get, :post and :head http method types are allowed.")
40
+
41
+ end
42
+
43
+ end
44
+
45
+ context "read timeout configuration" do
46
+ let(:client) { mock.as_null_object }
47
+
48
+ let(:http) { mock(Net::HTTP).as_null_object }
49
+
50
+ subject { Koha::Connection.new }
51
+
52
+ before do
53
+ Net::HTTP.stub(:new) { http }
54
+ end
55
+
56
+ it "should configure Net:HTTP read_timeout" do
57
+ http.should_receive(:read_timeout=).with(42)
58
+ subject.execute client, {:uri => URI.parse("http://localhost/some_uri"), :method => :get, :read_timeout => 42}
59
+ end
60
+
61
+ it "should use Net:HTTP default read_timeout if not specified" do
62
+ http.should_not_receive(:read_timeout=)
63
+ subject.execute client, {:uri => URI.parse("http://localhost/some_uri"), :method => :get}
64
+ end
65
+ end
66
+
67
+ context "open timeout configuration" do
68
+ let(:client) { mock.as_null_object }
69
+
70
+ let(:http) { mock(Net::HTTP).as_null_object }
71
+
72
+ subject { Koha::Connection.new }
73
+
74
+ before do
75
+ Net::HTTP.stub(:new) { http }
76
+ end
77
+
78
+ it "should configure Net:HTTP open_timeout" do
79
+ http.should_receive(:open_timeout=).with(42)
80
+ subject.execute client, {:uri => URI.parse("http://localhost/some_uri"), :method => :get, :open_timeout => 42}
81
+ end
82
+
83
+ it "should use Net:HTTP default open_timeout if not specified" do
84
+ http.should_not_receive(:open_timeout=)
85
+ subject.execute client, {:uri => URI.parse("http://localhost/some_uri"), :method => :get}
86
+ end
87
+ end
88
+
89
+ context "connection refused" do
90
+ let(:client) { mock.as_null_object }
91
+
92
+ let(:http) { mock(Net::HTTP).as_null_object }
93
+ let(:request_context) {
94
+ {:uri => URI.parse("http://localhost/some_uri"), :method => :get, :open_timeout => 42}
95
+ }
96
+ subject { Koha::Connection.new }
97
+
98
+ before do
99
+ Net::HTTP.stub(:new) { http }
100
+ end
101
+
102
+ it "should configure Net:HTTP open_timeout" do
103
+ http.should_receive(:request).and_raise(Errno::ECONNREFUSED)
104
+ lambda {
105
+ subject.execute client, request_context
106
+ }.should raise_error(Errno::ECONNREFUSED, /#{request_context}/)
107
+ end
108
+
109
+ # there is a strange ruby bug about closing a connection....this catches it.
110
+ it "should raise NoMethodError if a non-method is called" do
111
+ http.should_receive(:request).and_raise(NoMethodError)
112
+ lambda {
113
+ subject.execute client, request_context
114
+ }.should raise_error(NoMethodError, /NoMethodError/)
115
+ end
116
+
117
+ it "should raise NoMethodError if a non-method is called" do
118
+ error = NoMethodError.new("undefined method `closed?' for nil:NilClass")
119
+ http.should_receive(:request).and_raise(error)
120
+ lambda {
121
+ subject.execute client, request_context
122
+ }.should raise_error(Errno::ECONNREFUSED)
123
+ end
124
+
125
+ end
126
+
127
+ describe "basic auth support" do
128
+ let(:http) { mock(Net::HTTP).as_null_object }
129
+
130
+ before do
131
+ Net::HTTP.stub(:new) { http }
132
+ end
133
+
134
+ it "sets the authorization header" do
135
+ http.should_receive(:request) do |request|
136
+ request.fetch('authorization').should == "Basic #{Base64.encode64("joe:pass")}".strip
137
+ mock(Net::HTTPResponse).as_null_object
138
+ end
139
+ Koha::Connection.new.execute nil, :uri => URI.parse("http://joe:pass@localhost/koha/rest.pl"), :method => :get
140
+ end
141
+ end
142
+
143
+ describe "proxy support" do
144
+ it "set the proxy" do
145
+ @mock_proxy = mock('Proxy')
146
+ @mock_proxy.should_receive(:new).with("localhost", 80).and_return( mock(Net::HTTP).as_null_object)
147
+ Net::HTTP.should_receive(:Proxy).with("proxy", 80, nil, nil).and_return(@mock_proxy)
148
+ Koha::Connection.new.execute nil, :uri => URI.parse("http://localhost/koha/rest.pl"), :method => :get, :proxy => URI.parse("http://proxy/pass.pl")
149
+ end
150
+ end
151
+
152
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+ describe "Koha::Uri" do
3
+
4
+ context "class-level methods" do
5
+
6
+ let(:uri){ Koha::Uri }
7
+
8
+ it "should return a URI object with a trailing slash" do
9
+ u = uri.create 'http://koha.org'
10
+ u.path[0].should == ?/
11
+ end
12
+
13
+ it "should return the bytesize of a string" do
14
+ uri.bytesize("test").should == 4
15
+ end
16
+
17
+
18
+
19
+ context "escape_query_value" do
20
+
21
+ it 'should escape &' do
22
+ uri.to_params(:biblionumber => "&").should == 'biblionumber=%26'
23
+ end
24
+
25
+ it 'should escape &' do
26
+ uri.to_params({:biblionumber => "&" }, false).should == 'biblionumber=&'
27
+ end
28
+
29
+ it 'should escape &' do
30
+ uri.to_params(:biblionumber => [1,2,3] ).should == 'biblionumber=1+2+3'
31
+ end
32
+
33
+
34
+ it 'should convert spaces to +' do
35
+ uri.to_params(:biblionumber => "me and you").should == 'biblionumber=me+and+you'
36
+ end
37
+
38
+ it 'should escape comlex queries, part 1' do
39
+ my_params = {'fq' => '{!raw f=field_name}crazy+\"field+value'}
40
+ expected = 'fq=%7B%21raw+f%3Dfield_name%7Dcrazy%2B%5C%22field%2Bvalue'
41
+ uri.to_params(my_params).should == expected
42
+ end
43
+
44
+ it 'should escape complex queries, part 2' do
45
+ my_params = {'q' => '+popularity:[10 TO *] +section:0'}
46
+ expected = 'q=%2Bpopularity%3A%5B10+TO+%2A%5D+%2Bsection%3A0'
47
+ uri.to_params(my_params).should == expected
48
+ end
49
+
50
+ it 'should escape properly' do
51
+ uri.escape_query_value('+').should == '%2B'
52
+ uri.escape_query_value('This is a test').should == 'This+is+a+test'
53
+ uri.escape_query_value('<>/\\').should == '%3C%3E%2F%5C'
54
+ uri.escape_query_value('"').should == '%22'
55
+ uri.escape_query_value(':').should == '%3A'
56
+ end
57
+
58
+ it 'should escape brackets' do
59
+ uri.escape_query_value('{').should == '%7B'
60
+ uri.escape_query_value('}').should == '%7D'
61
+ end
62
+
63
+ it 'should escape exclamation marks!' do
64
+ uri.escape_query_value('!').should == '%21'
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,8 @@
1
+ require File.expand_path('../../lib/koha', __FILE__)
2
+ require 'webmock/rspec'
3
+ if ENV["COVERAGE"] == 'yes'
4
+ require 'simplecov'
5
+ SimpleCov.start do
6
+ add_filter 'spec'
7
+ end
8
+ end
@@ -0,0 +1,28 @@
1
+ require "rubygems"
2
+ require 'rspec'
3
+ require 'rspec/core/rake_task'
4
+
5
+ namespace :spec do
6
+
7
+ desc 'run api specs (mock out Koha dependency)'
8
+ RSpec::Core::RakeTask.new(:api) do |t|
9
+
10
+ t.pattern = [File.join('spec', 'spec_helper.rb')]
11
+ t.pattern += FileList[File.join('spec', 'api', '**', '*_spec.rb')]
12
+
13
+ t.verbose = true
14
+ t.rspec_opts = ['--color']
15
+ end
16
+ =begin
17
+ desc 'run integration specs'
18
+ RSpec::Core::RakeTask.new(:integration) do |t|
19
+
20
+ t.pattern = [File.join('spec', 'spec_helper.rb')]
21
+ t.pattern += FileList[File.join('spec', 'integration', '**', '*_spec.rb')]
22
+
23
+ t.verbose = true
24
+ t.rspec_opts = ['--color']
25
+ end
26
+ =end
27
+
28
+ end
@@ -0,0 +1,6 @@
1
+ require 'yard'
2
+
3
+ YARD::Rake::YardocTask.new do |t|
4
+ t.files = ['lib/**/*.rb'] # optional
5
+ t.options = ['--any', '--extra', '--opts'] # optional
6
+ end
metadata ADDED
@@ -0,0 +1,178 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: koha
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - chris fitzpatrick
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: simplecov
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - '='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.7.1
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - '='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.7.1
30
+ - !ruby/object:Gem::Dependency
31
+ name: yard
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.8.4.1
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.8.4.1
46
+ - !ruby/object:Gem::Dependency
47
+ name: webmock
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 1.9.3
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.9.3
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 10.0.3
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 10.0.3
78
+ - !ruby/object:Gem::Dependency
79
+ name: rdoc
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 3.9.5
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 3.9.5
94
+ - !ruby/object:Gem::Dependency
95
+ name: rspec
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 2.6.0
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 2.6.0
110
+ - !ruby/object:Gem::Dependency
111
+ name: redcarpet
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: ! 'Easy interface for the Koha ILSDI API (https://github.com/Koha-Community/Koha/blob/master/C4/ILSDI/Services.pm) '
127
+ email:
128
+ - chrisfitzpat@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - .gitignore
134
+ - .travis.yml
135
+ - CHANGELOG
136
+ - Gemfile
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - koha.gemspec
141
+ - lib/koha.rb
142
+ - lib/koha/client.rb
143
+ - lib/koha/connection.rb
144
+ - lib/koha/error.rb
145
+ - lib/koha/uri.rb
146
+ - lib/koha/version.rb
147
+ - spec/api/client_spec.rb
148
+ - spec/api/connection_spec.rb
149
+ - spec/api/uri_spec.rb
150
+ - spec/spec_helper.rb
151
+ - tasks/spec.rake
152
+ - tasks/yard.rake
153
+ homepage:
154
+ licenses: []
155
+ post_install_message:
156
+ rdoc_options: []
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ none: false
161
+ requirements:
162
+ - - ! '>='
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ none: false
167
+ requirements:
168
+ - - ! '>='
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ requirements: []
172
+ rubyforge_project:
173
+ rubygems_version: 1.8.24
174
+ signing_key:
175
+ specification_version: 3
176
+ summary: A Ruby client for Koha ILSDI interface
177
+ test_files: []
178
+ has_rdoc: