xporter_on_demand 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ceaf91f7c0ce11f34fde81948b9995d0d6ca9897
4
+ data.tar.gz: a815f2fa6e86d7fafcb1757e9082c8b6ca5b30cb
5
+ SHA512:
6
+ metadata.gz: 929d0d0e4609629fca2d12742b789e0f5983187a0b7c6fcd6065c2b996fa4313a98d7240606d2c6dc6012c59df409174840ceb007f6418fbb03d3cdc36ed3e9a
7
+ data.tar.gz: de14cee9e7c8b1fc5b606b9e48cb0b57de480e8ec2bcc82398eb6ea914dad412f36d6289df2aa1ec2673887a4fab5b0ae41da46d734241c2303895f8e2465fd9
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.15.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in xporter_on_demand.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Jordan Green
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # A Ruby client for the [XporterOnDemand API](https://xporter.groupcall.com/)
2
+
3
+ ## Installation
4
+ ```
5
+ gem install xod_client
6
+ ```
7
+
8
+ ## Getting started
9
+ ```ruby
10
+ require 'xporter_on_demand'
11
+
12
+ relying_party = "app.example.com" # Your relying party
13
+ school_estab = "1234567" # School establishment number
14
+ estab_secret = "YOUR SECRET HERE" # Supplied school secret
15
+
16
+ # Retrieve an IDAAS Authentication token
17
+ token = XporterOnDemand::Token.new(school_estab, relying_party, estab_secret).retrieve
18
+ # Initialize a client with the token
19
+ client = XporterOnDemand::Client.new(token.token)
20
+
21
+ # Craft a query with your desired options & parameters
22
+ students_endpoint = XporterOnDemand::Endpoint.create(:students, options: [:include_group_ids, :include_att_stats], parameters: { student_status: 'OnRoll' })
23
+
24
+ # Fetch the first page of results
25
+ student_results = client.query(students_endpoint)
26
+ # Retrieve all pages
27
+ student_results.fetch_all
28
+ ```
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "xporter_on_demand"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,32 @@
1
+ module XporterOnDemand
2
+ module API
3
+ def fetch(endpoint)
4
+ raise ArgumentError, "endpoint must contain 'id' parameter" unless endpoint.id
5
+ create_result_set(get_endpoint(endpoint), endpoint)
6
+ end
7
+
8
+ def query(endpoint)
9
+ create_result_set(get_endpoint(endpoint), endpoint)
10
+ end
11
+
12
+ def changed_rows(endpoint)
13
+ raise ArgumentError, "endpoint must contain 'changed_rows' parameter" unless endpoint.parameters[:changed_rows]
14
+ create_result_set(get_endpoint(endpoint), endpoint)
15
+ end
16
+
17
+ def db_status(resource)
18
+ create_result_set(get(@uri + resource.to_s.camelize + "/?onlyGetDbStatus=true"))
19
+ end
20
+
21
+ def get_endpoint(endpoint)
22
+ get(@uri + endpoint.build_query)
23
+ end
24
+
25
+ private
26
+ def create_result_set(results, endpoint = nil)
27
+ XporterOnDemand::ResultSet.new(results).tap do |rs|
28
+ rs.attach_stuff(self, endpoint) if endpoint
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,43 @@
1
+ require 'httpi'
2
+ require 'json'
3
+ require 'active_support/core_ext/string'
4
+ require 'xporter_on_demand/utils'
5
+
6
+ module XporterOnDemand
7
+ class Client
8
+ include XporterOnDemand::API
9
+ include XporterOnDemand::Utils
10
+
11
+ attr_reader :token, :available_scopes, :estab, :uri
12
+
13
+ def initialize(token = nil, args = {})
14
+ @token = token
15
+ @args = args
16
+
17
+ details = token_details
18
+ @available_scopes = details["Scopes"]
19
+ @estab = @args.delete(:estab)
20
+ @estab ||= details["Estab"]
21
+
22
+ args[:edubase] ? edubase_client : school_client
23
+ end
24
+
25
+ %i(token_details scopes queries logs usage).each do |endpoint|
26
+ define_method(endpoint){ get_info(endpoint.to_s.camelcase) }
27
+ end
28
+
29
+ def school_client
30
+ @uri = API_PATH + "School/" + estab + "/"
31
+ end
32
+
33
+ # This is not finished and probably won't even work.
34
+ def edubase_client
35
+ @uri = API_PATH + "RunQuery/?"
36
+ end
37
+
38
+ private
39
+ def get_info(endpoint)
40
+ get(url: API_PATH + endpoint)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,53 @@
1
+ require 'xporter_on_demand/factory'
2
+
3
+ module XporterOnDemand
4
+ class Endpoint
5
+ include XporterOnDemand::Utils
6
+
7
+ attr_accessor :endpoint, :options, :parameters, :pagination, :uri, :id
8
+
9
+ def self.create(endpoint, args = {})
10
+ endpoint_name = endpoint.to_s.classify
11
+
12
+ unless const_defined?(endpoint_name, false)
13
+ class_name = Class.new(self)
14
+ endpoint_class = const_set(endpoint_name, class_name)
15
+ end
16
+
17
+ const_get(endpoint_name).new(args).tap do |s|
18
+ s.instance_variable_set(:@endpoint, endpoint)
19
+ end
20
+ end
21
+
22
+ def initialize(args = {})
23
+ @options = args.fetch(:options, [])
24
+ @parameters = args.fetch(:parameters, {})
25
+
26
+ @parameters[:page] ||= 1
27
+ @parameters[:page_size] ||= 25
28
+
29
+ @id = args[:id]
30
+
31
+ # Check that all the options are valid?
32
+ # Check that the parameters are valid?
33
+ # Check the pagination params are valid?
34
+ end
35
+
36
+ def build_query
37
+ URI.escape(resource + "?" + build_parameters)
38
+ end
39
+
40
+ private
41
+ def resource
42
+ endpoint.to_s.camelize + "/" + (@id || "")
43
+ end
44
+
45
+ def build_options
46
+ @options.any? ? ["options=" + @options.map{ |o| parameterize(o) }.join(',')] : []
47
+ end
48
+
49
+ def build_parameters
50
+ (@parameters.map{ |k, v| parameterize(k) + "=" + v.to_s } + build_options).join('&')
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,19 @@
1
+ module XporterOnDemand
2
+ module Factory
3
+ def self.create(name, superclass, args = {})
4
+ i_vars = args.delete(:i_vars) || {}
5
+ namespace = args.delete(:namespace) || superclass
6
+
7
+ unless namespace.const_defined?(name, false)
8
+ s_class = Class.new(superclass)
9
+ namespace.const_set(name, s_class)
10
+ end
11
+
12
+ namespace.const_get(name).new(args).tap do |klass|
13
+ i_vars.each do |i_var, value|
14
+ klass.instance_variable_set(i_var, value)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ module XporterOnDemand
2
+ module Result
3
+ class Base
4
+ include XporterOnDemand::Utils
5
+
6
+ def initialize(args = {})
7
+ result = args.delete(:result)
8
+ assign_attributes(result)
9
+ end
10
+
11
+ def type
12
+ self.class.name.demodulize
13
+ end
14
+
15
+ def update(other_result)
16
+ return if other_result.type != type ||\
17
+ other_result.id != id ||\
18
+ other_result.last_updated <= last_updated
19
+
20
+ attributes.each do |attribute|
21
+ send("#{attribute}=", other_result.send(attribute))
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,82 @@
1
+ module XporterOnDemand
2
+ class ResultSet
3
+ include Enumerable
4
+ include XporterOnDemand::Utils
5
+
6
+ attr_accessor :results, :school, :endpoint
7
+
8
+ def initialize(result_hash)
9
+ results = create_results(result_hash)
10
+ assign_attributes results
11
+ end
12
+
13
+ def each
14
+ all.each{ |result| yield result }
15
+ end
16
+
17
+ def all
18
+ attributes.reject{ |a| META_KEYS.include? a.camelcase }.flat_map{ |a| send(a) }
19
+ end
20
+
21
+ def length
22
+ all.length
23
+ end
24
+
25
+ def fetch_all
26
+ return self unless try :pagination
27
+ og_page = pagination.page_number
28
+
29
+ pagination.page_count.times do |i|
30
+ # Skip if we've already got this page
31
+ next if og_page == i + 1
32
+
33
+ endpoint.parameters[:page] = i + 1
34
+
35
+ results_hash = create_results(school.get_endpoint(endpoint))
36
+
37
+ results_hash.each do |type, results|
38
+ if META_KEYS.include? type.camelcase
39
+ assign_attributes(type => results)
40
+ elsif self.respond_to?(type)
41
+ results.each do |result|
42
+ if result.respond_to?(:id) && existing_result = send(type).find{ |r| r.id == result.id }
43
+ existing_result.update(result)
44
+ else
45
+ send(type).append(result)
46
+ end
47
+ end
48
+ else
49
+ assign_attributes(type => results)
50
+ end
51
+ end
52
+ end
53
+ self
54
+ end
55
+
56
+ def attach_stuff(sch, ep)
57
+ self.school = sch
58
+ self.endpoint = ep.dup
59
+ end
60
+
61
+ private
62
+ def create_results(result_hash)
63
+ result_hash.map do |namespace, objects|
64
+ type = namespace.underscore.camelize
65
+ result_objects = objects.flat_map{ |object| create_result(type, object) }
66
+
67
+ [namespace.underscore, result_objects]
68
+ end.to_h
69
+ end
70
+
71
+ # def create_result(type, object)
72
+ # Factory.create(
73
+ # META_KEYS.include?(type) ? type : type.singularize,
74
+ # XporterOnDemand::Result::Base,
75
+ # {
76
+ # namespace: XporterOnDemand::Result,
77
+ # result: object
78
+ # }
79
+ # )
80
+ # end
81
+ end
82
+ end
@@ -0,0 +1,57 @@
1
+ module XporterOnDemand
2
+ module Result
3
+ class Serialiser
4
+ FORMAT_REGISTRY = Hash.new{ |h, k| h[k] = { type: :default } }.update(
5
+ active: { type: :boolean },
6
+ date: { type: :date },
7
+ dateof_birth: { type: :date },
8
+ date_of_birth: { type: :date },
9
+ date_time: { type: :date_time },
10
+ eal: { type: :boolean },
11
+ expires: { type: :date_time },
12
+ fsm_eligible: { type: :boolean },
13
+ fsm_ever6: { type: :boolean },
14
+ gifted: { type: :boolean },
15
+ in_lea_care: { type: :boolean },
16
+ last_updated: { type: :date_time },
17
+ par_resp: { type: :boolean },
18
+ pupil_premium: { type: :boolean },
19
+ service_child: { type: :boolean },
20
+ uniform_allowance: { type: :boolean }
21
+ )
22
+
23
+ FORMATTERS = {
24
+ boolean: ->(v){ !!v.nonzero? },
25
+ csv: ->(v){ v.split(',') rescue [] },
26
+ date: ->(v){ Date.parse(v) rescue nil },
27
+ date_time: ->(v){ DateTime.parse(v) rescue nil },
28
+ default: ->(v){ v },
29
+ }
30
+
31
+ def self.serialise(attributes)
32
+ object_array = attributes.map do |attribute, value|
33
+ key = attribute.underscore
34
+ format = get_format(key)
35
+
36
+ [key, FORMATTERS[format].call(value)]
37
+ end
38
+ object_array.to_h
39
+ end
40
+
41
+ private
42
+ def self.get_format(key)
43
+ if key =~ /_ids\z/
44
+ :csv
45
+ elsif key =~ /(_?date\z|(start|end)\z)/
46
+ :date
47
+ elsif key =~ /_date_time\z/
48
+ :date_time
49
+ elsif key =~ /\Ais_/
50
+ :boolean
51
+ else
52
+ FORMAT_REGISTRY[key.to_sym][:type]
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,20 @@
1
+ module XporterOnDemand
2
+ class Token < Client
3
+ def initialize(*args)
4
+ @options = args.last.is_a?(Hash) ? args.pop : {}
5
+ @options[:url] ||= STS_PATH
6
+
7
+ @request_body = {}
8
+ %w(estab relyingParty password thirdpartyid).each_with_index{ |k, i| @request_body[k] = args[i] }
9
+
10
+ @request_body["thirdpartyid"] ||= "XporterOnDemand"
11
+ raise ArgumentError, "must supply all the sniz" unless @request_body.none?{ |k, v| v.nil? }
12
+ end
13
+
14
+ def retrieve
15
+ result = post(@options.merge(body: @request_body.to_json))
16
+ assign_attributes(result)
17
+ self
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,68 @@
1
+ module XporterOnDemand
2
+ module Utils
3
+ [:get, :post].each do |verb|
4
+ define_method(verb) do |*args|
5
+ request = configure_request(*args)
6
+ response = HTTPI.request(verb, request)
7
+ handle_exceptions(response)
8
+ JSON.parse(response.body.presence || {})
9
+ end
10
+ end
11
+
12
+ def configure_request(*args)
13
+ request = HTTPI::Request.new(*args)
14
+ request.headers["Content-Type"] = "application/json"
15
+ request.headers["Authorization"] = "Idaas " + @token if @token
16
+ request
17
+ end
18
+
19
+ def handle_exceptions(response)
20
+ response_body = JSON.parse(response.body || {})
21
+ raise response_body["ExceptionMessage"] if response_body["ExceptionMessage"]
22
+ end
23
+
24
+ def parameterize(sym)
25
+ sym.to_s.camelize(:lower)
26
+ end
27
+
28
+ def assign_attributes(attributes)
29
+ unless instance_variable_defined?("@attributes")
30
+ instance_variable_set("@attributes", [])
31
+ self.class.send(:attr_reader, :attributes)
32
+ end
33
+
34
+ XporterOnDemand::Result::Serialiser.serialise(attributes).each do |name, value|
35
+ method_name = name.camelize.underscore
36
+ unless META_KEYS.include?(name.camelize)
37
+ method_name = method_name.singularize if value.is_a?(Array) && value.length == 1
38
+ end
39
+
40
+ instance_variable_set("@#{method_name}", unwrap(value))
41
+ self.class.send(:attr_reader, method_name)
42
+
43
+ @attributes |= [method_name]
44
+ end
45
+ end
46
+
47
+ def create_result(type, object)
48
+ Factory.create(
49
+ META_KEYS.include?(type) ? type : type.singularize,
50
+ XporterOnDemand::Result::Base,
51
+ {
52
+ namespace: XporterOnDemand::Result,
53
+ result: object,
54
+ }
55
+ )
56
+ end
57
+
58
+ def unwrap(enum)
59
+ if enum.is_a?(Array)
60
+ enum.length <= 1 ? enum.first || [] : enum
61
+ elsif enum.is_a?(Hash)
62
+ enum.length == 1 ? unwrap(enum[enum.keys.first]) : enum
63
+ else
64
+ enum
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module XporterOnDemand
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,22 @@
1
+ # require "xporter_on_demand/version"
2
+ # require 'xporter_on_demand/client'
3
+ # require 'xporter_on_demand/token'
4
+ # # require 'xporter_on_demand/utils'
5
+ # require 'xporter_on_demand/result/serialiser'
6
+
7
+ require 'xporter_on_demand/api'
8
+ require 'xporter_on_demand/client'
9
+ require 'xporter_on_demand/endpoint'
10
+ require 'xporter_on_demand/factory'
11
+ require 'xporter_on_demand/token'
12
+ require 'xporter_on_demand/utils'
13
+ require 'xporter_on_demand/version'
14
+ require 'xporter_on_demand/result/base'
15
+ require 'xporter_on_demand/result/result_set'
16
+ require 'xporter_on_demand/result/serialiser'
17
+
18
+ module XporterOnDemand
19
+ API_PATH = "https://xporter.groupcall.com/api/v1/"
20
+ STS_PATH = "https://login.groupcall.com/idaas/sts/STS/GetToken"
21
+ META_KEYS = %w(ChangedRows DbStatus Meta Pagination)
22
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "xporter_on_demand/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "xporter_on_demand"
8
+ spec.version = XporterOnDemand::VERSION
9
+ spec.authors = ["Jordan Green"]
10
+ spec.email = ["jordan.green@meritec.co.uk"]
11
+
12
+ spec.summary = %q{Ruby client for the Xporter on Demand API.}
13
+ spec.homepage = "https://github.com/meritec/xporter_on_demand"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_runtime_dependency 'httpi', '~> 2.4.2', '>= 2.4.2'
24
+ # Gotta use httpclient cos net_http don't like the __foo__ JSON keys
25
+ spec.add_runtime_dependency 'httpclient', '~> 2.8.3', '>= 2.8.3'
26
+ spec.add_runtime_dependency 'activesupport', '~> 5.0.0.1', '>= 5.0.0.1'
27
+ spec.add_development_dependency "bundler", "~> 1.15"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "minitest", "~> 5.0"
30
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xporter_on_demand
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jordan Green
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-12-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httpi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.4.2
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.4.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 2.4.2
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.4.2
33
+ - !ruby/object:Gem::Dependency
34
+ name: httpclient
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 2.8.3
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 2.8.3
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 2.8.3
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 2.8.3
53
+ - !ruby/object:Gem::Dependency
54
+ name: activesupport
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 5.0.0.1
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 5.0.0.1
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 5.0.0.1
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 5.0.0.1
73
+ - !ruby/object:Gem::Dependency
74
+ name: bundler
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '1.15'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '1.15'
87
+ - !ruby/object:Gem::Dependency
88
+ name: rake
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: '10.0'
94
+ type: :development
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '10.0'
101
+ - !ruby/object:Gem::Dependency
102
+ name: minitest
103
+ requirement: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - "~>"
106
+ - !ruby/object:Gem::Version
107
+ version: '5.0'
108
+ type: :development
109
+ prerelease: false
110
+ version_requirements: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - "~>"
113
+ - !ruby/object:Gem::Version
114
+ version: '5.0'
115
+ description:
116
+ email:
117
+ - jordan.green@meritec.co.uk
118
+ executables: []
119
+ extensions: []
120
+ extra_rdoc_files: []
121
+ files:
122
+ - ".gitignore"
123
+ - ".travis.yml"
124
+ - Gemfile
125
+ - LICENSE.txt
126
+ - README.md
127
+ - Rakefile
128
+ - bin/console
129
+ - bin/setup
130
+ - lib/xporter_on_demand.rb
131
+ - lib/xporter_on_demand/api.rb
132
+ - lib/xporter_on_demand/client.rb
133
+ - lib/xporter_on_demand/endpoint.rb
134
+ - lib/xporter_on_demand/factory.rb
135
+ - lib/xporter_on_demand/result/base.rb
136
+ - lib/xporter_on_demand/result/result_set.rb
137
+ - lib/xporter_on_demand/result/serialiser.rb
138
+ - lib/xporter_on_demand/token.rb
139
+ - lib/xporter_on_demand/utils.rb
140
+ - lib/xporter_on_demand/version.rb
141
+ - xporter_on_demand.gemspec
142
+ homepage: https://github.com/meritec/xporter_on_demand
143
+ licenses:
144
+ - MIT
145
+ metadata: {}
146
+ post_install_message:
147
+ rdoc_options: []
148
+ require_paths:
149
+ - lib
150
+ required_ruby_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ requirements: []
161
+ rubyforge_project:
162
+ rubygems_version: 2.6.12
163
+ signing_key:
164
+ specification_version: 4
165
+ summary: Ruby client for the Xporter on Demand API.
166
+ test_files: []