itglue 0.1.0

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 577a952aa71445a0982220ba9519ef3e8ff30abb
4
+ data.tar.gz: e00b1ce90a9bcd6a9b56935b72ad3953b85dcde0
5
+ SHA512:
6
+ metadata.gz: 430a99fea58b66419afbefa28449d4bc3cedf0b3e457c9e61bce8e3b6b131c6585d94b0dacb39e8b22bb5acd5019c3993dc7d5b0012cb0711d06c6f4ac049285
7
+ data.tar.gz: 1ca0c09f3127a634d5dd087a38666ed8bbbb9a8cd6007569bfa86a6d539dd3a1e9c23409777e767c63ecf8191ef49f811cda42538b2f1db47f086806120f9ae7
@@ -0,0 +1,12 @@
1
+ Gemfile.lock
2
+ .DS_Store
3
+ /.bundle/
4
+ /.yardoc
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ .rspec_status
12
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in itglue.gemspec
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Ben Silva
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.
@@ -0,0 +1,104 @@
1
+ # ITGlue
2
+
3
+ A wrapper for the [ITGlue API](https://api.itglue.com/developer/).
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ gem 'itglue'
9
+ ```
10
+
11
+ ## Requirements
12
+
13
+ * Ruby 2.0.0 or higher
14
+
15
+ ## Setup
16
+
17
+ ### Authentication
18
+
19
+ For now this gem only supports API Key authentication.
20
+
21
+ ### Configuration
22
+
23
+ ```ruby
24
+ require 'itglue'
25
+
26
+ ITGlue.configure do |config|
27
+ config.itglue_api_key = 'ITG.b94e901420fe7cb163a364b451f172d9.P3nMIV9EDp1Xb7h4-sO7WDU0S2R5DgC-fu2DsTxBkW7eZHRp0y4ODRQ51se1c24m' config.itglue_api_base_uri = 'https://api.itglue.com'
28
+ config.logger = ::Logger.new(STDOUT)
29
+ end
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ### Basics
35
+
36
+ Get all organizations
37
+ ```ruby
38
+ organizations = ITGlue::Organization.get
39
+ #=> [#<ITGlue::Organization id: 123 name: "Happy Frog", description: nil, ...>, <ITGlue::Organization id: 124 name: "Vancity Superstars", description: nil, ...>, ...]
40
+ ```
41
+ Get organizations with a filter
42
+ ```ruby
43
+ organizations = ITGlue::Organization.filter(name: 'Happy Frog')
44
+ #=> [#<ITGlue::Organization id: 123 name: "Happy Frog", description: nil, ...>]
45
+ ```
46
+ Get organization by id
47
+ ```ruby
48
+ organization = ITGlue::Organization.find(123)
49
+ #=> #<ITGlue::Organization id: 123 name: "Ben's Gem Test", description: nil, ...>]
50
+ ```
51
+ Get configurations for a specific organization
52
+ ```ruby
53
+ configuration = ITGlue::Organization.get_nested(organization)
54
+ ```
55
+
56
+ ### Client
57
+
58
+ You can also directly instantiate a client and handle the data and response directly.
59
+ ```ruby
60
+ client = ITGlue::Client.new
61
+ #=> #<ITGlue::Client:0x007fd7eb032d00 ...>
62
+ query = { filter: { name: 'HP' } }
63
+ client.get(:configurations, { parent: organization }, { query: query })
64
+ # => [
65
+ # {
66
+ # id: 456,
67
+ # type: "configurations",
68
+ # attributes: {
69
+ # organization_id: 123,
70
+ # organization_name: "Happy Frog",
71
+ # ...
72
+ # }
73
+ # },
74
+ # ...
75
+ # ]
76
+ ```
77
+ A get request such as the one above will handle generating the route and pagination. If you want to handle these yourself, you can use 'execute'
78
+ ```ruby
79
+ client.execute(:get, '/organizations/31131/relationships/configurations', nil, {query: {filter: {name: 'HP'}}})
80
+ # => {
81
+ # "data"=> [
82
+ # {
83
+ # "id"=>"23943",
84
+ # "type"=>"configurations",
85
+ # "attributes"=> {
86
+ # "organization-id"=>31131,
87
+ # "organization-name"=>"Ben's Gem Test",
88
+ # ...
89
+ # }
90
+ # },
91
+ # ...
92
+ # ],
93
+ # "links"=>{},
94
+ # "meta"=>{"current-page"=>1, "next-page"=>nil, "prev-page"=>nil, "total-pages"=>1, "total-count"=>1, "filters"=>{}}
95
+ # }
96
+ ```
97
+
98
+ ## Contributing
99
+
100
+ Bug reports and pull requests are welcome on GitHub at https://github.com/b-loyola/itglue.
101
+
102
+ ## License
103
+
104
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "itglue"
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__)
@@ -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,30 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "itglue/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "itglue"
8
+ spec.version = ITGlue::VERSION
9
+ spec.authors = ["Ben Silva"]
10
+ spec.email = ["berna.loyola@gmail.com"]
11
+
12
+ spec.summary = %q{A simple wrapper for the IT Glue API}
13
+ spec.description = %q{This gem provides a client for interactiong with the IT Glue API}
14
+ spec.homepage = "https://github.com/b-loyola/itglue"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.16"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+
28
+ spec.add_dependency "httparty", "~> 0.16", ">= 0.15.7"
29
+ spec.add_dependency "activesupport", "~> 5.2", ">= 3.0.0"
30
+ end
@@ -0,0 +1,29 @@
1
+ module ITGlue
2
+ class ITGlueError < StandardError; end
3
+
4
+ class << self
5
+ attr_writer :config
6
+
7
+ def config
8
+ @config ||= Config.new
9
+ end
10
+
11
+ def configure
12
+ yield(config)
13
+ config
14
+ end
15
+ end
16
+
17
+ class Config
18
+ DEFAULT_PAGE_SIZE = 500
19
+ attr_accessor :itglue_api_key, :itglue_api_base_uri, :logger, :default_page_size
20
+
21
+ def initialize
22
+ @default_page_size = DEFAULT_PAGE_SIZE
23
+ end
24
+ end
25
+ end
26
+
27
+ require 'itglue/version'
28
+ require 'itglue/client'
29
+ require 'itglue/asset'
@@ -0,0 +1,8 @@
1
+ Dir[File.join(File.dirname(__FILE__), 'asset/*.rb')].each {|file| require file }
2
+
3
+ module ITGlue
4
+ module Asset
5
+ class ITGlueAssetError < ITGlueError; end
6
+ class MethodNotAvailable < ITGlueAssetError; end
7
+ end
8
+ end
@@ -0,0 +1,180 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+ require 'itglue/asset/base/relatable'
3
+ require 'itglue/asset/base/attributes'
4
+
5
+ module ITGlue
6
+ module Asset
7
+ class Base
8
+ extend Relatable
9
+
10
+ class << self
11
+ # Override in subclasses if required
12
+ def asset_type
13
+ raise ITGlueAssetError.new('no asset_type for base') if self == Base
14
+ self.name.demodulize.pluralize.underscore.to_sym
15
+ end
16
+
17
+ # Instantiates a record from data payload
18
+ # @param data [Hash] the data payload
19
+ # E.g.: { id: 1, type: 'organizations', attributes: {name: 'Happy Frog', ...} }
20
+ # @return [ITGlue::Asset] the record instance
21
+ def new_from_payload(data)
22
+ raise_method_not_available(__method__, 'not available for Base') if self == Base
23
+ asset = self.new(data[:attributes])
24
+ asset.id = data[:id]
25
+ asset.type = data[:type]
26
+ asset
27
+ end
28
+
29
+ # Executes a get request through the top-level path
30
+ # E.g. GET '/configurations'
31
+ # @return [Array<ITGlue::Asset>] an array of asset instances
32
+ def get
33
+ raise_method_not_available(__method__, 'is nested asset') if nested_asset?
34
+ assets = client.get(asset_type)
35
+ assets.map { |data| self.new_from_payload(data) }
36
+ end
37
+
38
+ # Executes a get request through the nested asset path
39
+ # E.g. GET 'organizations/:organization_id/relationships/configurations'
40
+ # @param parent [ITGlue::Asset] the parent asset
41
+ # @return [Array<ITGlue::Asset>] an array of asset instances
42
+ def get_nested(parent)
43
+ raise_method_not_available(__method__, 'is top-level asset') unless parent_type
44
+ path_options = { parent: parent }
45
+ assets = client.get(asset_type, path_options)
46
+ assets.map { |data| self.new_from_payload(data) }
47
+ end
48
+
49
+ # Executes a get request through the top-level path, with a filter query
50
+ # E.g. GET '/configurations?filter[name]=HP-01'
51
+ # @param filter [Hash|String] the parameters to filter by
52
+ # @return [Array<ITGlue::Asset>] an array of asset instances
53
+ def filter(filter)
54
+ raise_method_not_available(__method__, 'is nested asset') if nested_asset?
55
+ assets = client.get(asset_type, {}, { query: { filter: filter } })
56
+ assets.map { |data| self.new_from_payload(data) }
57
+ end
58
+
59
+ # Executes a get request through the top-level path for a specific asset
60
+ # E.g. GET '/configurations/1'
61
+ # @param id [Integer] the id of the asset
62
+ # @return [ITGlue::Asset] the asset instance
63
+ def find(id)
64
+ data = client.get(asset_type, id: id )
65
+ self.new_from_payload(data)
66
+ end
67
+
68
+ def client
69
+ @@client ||= Client.new
70
+ end
71
+
72
+ protected
73
+
74
+ def raise_method_not_available(method_name, reason)
75
+ error_msg = "method '#{method_name}' is not available for #{asset_type}: #{reason}"
76
+ raise MethodNotAvailable.new(error_msg)
77
+ end
78
+ end
79
+
80
+ attr_accessor :id, :type, :attributes
81
+
82
+ def initialize(attributes = {})
83
+ raise ITGlueAssetError.new('cannot instantiate base') if self == Base
84
+ @attributes = Attributes.new(attributes)
85
+ end
86
+
87
+ def asset_type
88
+ self.class.asset_type
89
+ end
90
+
91
+ def inspect
92
+ string = "#<#{self.class.name} id: #{self.id || 'nil'} "
93
+ fields = @attributes.keys.map { |field| "#{field}: #{@attributes.inspect_field(field)}" }
94
+ string << fields.join(", ") << ">"
95
+ end
96
+
97
+ def dup
98
+ dup = self.class.new(self.attributes)
99
+ dup.type = self.type
100
+ dup
101
+ end
102
+
103
+ def assign_attributes(attributes)
104
+ raise ArgumentError.new('attributtes must be a Hash') unless attributes.is_a?(Hash)
105
+ attributes.each do |attribute, value|
106
+ @attributes[attribute] = value
107
+ end
108
+ end
109
+
110
+ def changed_attributes
111
+ @attributes.changes
112
+ end
113
+
114
+ def remove_attribute(key)
115
+ @attributes.remove_attribute(key)
116
+ end
117
+
118
+ def new_asset?
119
+ !self.id
120
+ end
121
+
122
+ def save
123
+ new_asset? ? create : update
124
+ end
125
+
126
+ def changed?
127
+ !changed_attributes.empty?
128
+ end
129
+
130
+ def [](attribute)
131
+ @attributes[attribute]
132
+ end
133
+
134
+ def []=(attribute, value)
135
+ @attributes.assign_attribute(attribute, value)
136
+ end
137
+
138
+ def method_missing(method, *args)
139
+ method_name = method.to_s
140
+ arg_count = args.length
141
+ if method_name.chomp!('=')
142
+ raise ArgumentError.new("wrong number of arguments (#{arg_count} for 1)") if arg_count != 1
143
+ @attributes.assign_attribute(method_name, args[0])
144
+ elsif arg_count == 0
145
+ @attributes[method]
146
+ else
147
+ super
148
+ end
149
+ end
150
+
151
+ private
152
+
153
+ def create
154
+ data = self.class.client.post(asset_type, payload)
155
+ reload_from_data(data)
156
+ end
157
+
158
+ def update
159
+ data = self.class.client.patch(asset_type, payload, id: id )
160
+ reload_from_data(data)
161
+ end
162
+
163
+ def payload
164
+ {
165
+ data: {
166
+ type: asset_type,
167
+ attributes: attributes.attributes_hash
168
+ }
169
+ }
170
+ end
171
+
172
+ def reload_from_data(data)
173
+ @attributes = Attributes.new(data[:attributes])
174
+ self.type = data[:type]
175
+ self.id = data[:id]
176
+ self
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,44 @@
1
+ module ITGlue
2
+ module Asset
3
+ class Attributes < OpenStruct
4
+ def initialize(*args)
5
+ @changed_attribute_keys = []
6
+ super
7
+ end
8
+
9
+ def assign_attribute(key, value)
10
+ @changed_attribute_keys << key.to_sym
11
+ self[key] = value
12
+ end
13
+
14
+ def remove_attribute(key)
15
+ @changed_attribute_keys.delete(key)
16
+ self.delete_field(key)
17
+ end
18
+
19
+ def keys
20
+ self.to_h.keys
21
+ end
22
+
23
+ def attributes_hash
24
+ self.to_h
25
+ end
26
+
27
+ def inspect_field(field)
28
+ value = self[field]
29
+ if value.is_a?(String)
30
+ value.length > 100 ? "\"#{value[0..100]}...\"" : "\"#{value}\""
31
+ else
32
+ value.inspect
33
+ end
34
+ end
35
+
36
+ def changes
37
+ attributes_hash = self.attributes_hash
38
+ @changed_attribute_keys.each_with_object({}) do |key, changes|
39
+ changes[key] = attributes_hash[key]
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,37 @@
1
+ module ITGlue
2
+ module Asset
3
+ module Relatable
4
+ def parent(parent_type, options = {})
5
+ @parent_type = parent_type.to_s.pluralize
6
+ unless options[:no_association]
7
+ define_method parent_type do
8
+ parent_id = self.send("#{parent_type}_id")
9
+ "ITGlue::#{parent_type.to_s.classify}".constantize.find(parent_id)
10
+ end
11
+ end
12
+ end
13
+
14
+ def children(*child_types)
15
+ child_types.each do |child_type|
16
+ define_method child_type do |options = {}|
17
+ "ITGlue::#{child_type.to_s.classify}".constantize.get_nested(self, options)
18
+ end
19
+ end
20
+ end
21
+
22
+ protected
23
+
24
+ def nested_asset
25
+ @nested_asset = true
26
+ end
27
+
28
+ def nested_asset?
29
+ !!@nested_asset
30
+ end
31
+
32
+ def parent_type
33
+ @parent_type
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,6 @@
1
+ module ITGlue
2
+ class Configuration < Asset::Base
3
+ parent :organization
4
+ children :configuration_interfaces
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module ITGlue
2
+ class ConfigurationInterface < Asset::Base
3
+ parent :configuration, no_association: true
4
+ nested_asset
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ module ITGlue
2
+ class ConfigurationStatus < Asset::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ITGlue
2
+ class ConfigurationType < Asset::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ITGlue
2
+ class Organization < Asset::Base
3
+ end
4
+ end
@@ -0,0 +1,119 @@
1
+ require 'httparty'
2
+ require 'itglue/client/mapper'
3
+ require 'itglue/client/path_processor'
4
+
5
+ module ITGlue
6
+ class ClientError < ITGlueError; end
7
+ class AssetNotFoundError < ClientError; end
8
+ class ServerError < ClientError; end
9
+ class UnexpectedResponseError < ClientError; end
10
+
11
+ class Client
12
+ include HTTParty
13
+
14
+ def initialize
15
+ raise ClientError.new('itglue_api_key not configured') unless ITGlue.config.itglue_api_key
16
+ raise ClientError.new('itglue_api_base_uri not configured') unless ITGlue.config.itglue_api_base_uri
17
+ @itglue_api_key = ITGlue.config.itglue_api_key
18
+ @default_page_size = ITGlue.config.default_page_size
19
+ self.class.base_uri ITGlue.config.itglue_api_base_uri
20
+ self.class.logger ITGlue.config.logger
21
+ end
22
+
23
+ def execute(http_method, path, payload = nil, options = {})
24
+ process_request(http_method, path, payload, options)
25
+ end
26
+
27
+ def get(asset_type, path_options = {}, options = {})
28
+ response = process_request(:get, process_path(asset_type, path_options), nil, options)
29
+ data = get_remaining_data(response, options)
30
+ prepare_data(data)
31
+ end
32
+
33
+ def patch(asset_type, payload, path_options = {}, options = {})
34
+ response = process_request(:patch, process_path(asset_type, path_options), payload, options)
35
+ prepare_data(response['data'])
36
+ end
37
+
38
+ def post(asset_type, payload, path_options = {}, options = {})
39
+ response = process_request(:post, process_path(asset_type, path_options), payload, options)
40
+ prepare_data(response['data'])
41
+ end
42
+
43
+ private
44
+
45
+ def get_remaining_data(response, options)
46
+ return response['data'] unless response['data'].is_a?(Array)
47
+ data = response['data']
48
+ loop do
49
+ break if response['meta'] && response['meta']['next-page'].nil?
50
+ response = process_request(:get, response['links']['next'], nil, options)
51
+ data += response['data']
52
+ end
53
+ data
54
+ end
55
+
56
+ def default_headers
57
+ @default_headers ||= {
58
+ 'Content-Type' => 'application/vnd.api+json',
59
+ 'x-api-key' => @itglue_api_key
60
+ }
61
+ end
62
+
63
+ def process_path(asset_type, path_options)
64
+ PathProcessor.process(asset_type, path_options)
65
+ end
66
+
67
+ def prepare_data(data)
68
+ Mapper.map(data)
69
+ end
70
+
71
+ def process_request(http_method, path, payload, options)
72
+ options = process_options(options, payload)
73
+ response = self.class.send(http_method, path, options)
74
+ response.success? ? response : handle_response_errors(response)
75
+ end
76
+
77
+ def process_options(options, payload)
78
+ options.merge!(body: payload.to_json) if payload
79
+ options[:headers] = process_header_options(options[:headers])
80
+ options[:query] = process_query_options(options[:query])
81
+ options
82
+ end
83
+
84
+ def process_header_options(header_options)
85
+ return default_headers unless header_options
86
+ raise ClientError.new('header option must be a Hash') unless header_options.is_a?(Hash)
87
+ default_headers.merge(header_options)
88
+ end
89
+
90
+ def process_query_options(query_options)
91
+ return { page: { size: @default_page_size } } unless query_options
92
+ raise ClientError.new('query option must be a Hash') unless query_options.is_a?(Hash)
93
+ if query_options[:page]
94
+ raise ClientError.new('query page option must be a Hash') unless query_options[:page].is_a?(Hash)
95
+ query_options[:page][:size] ||= @default_page_size
96
+ else
97
+ query_options[:page] = { size: @default_page_size }
98
+ end
99
+ query_options
100
+ end
101
+
102
+ def handle_response_errors(response)
103
+ if response.not_found?
104
+ raise AssetNotFoundError.new(error_message(response))
105
+ elsif response.client_error?
106
+ raise ClientError.new(error_message(response))
107
+ elsif response.server_error?
108
+ raise ServerError.new(error_message(response))
109
+ else
110
+ raise UnexpectedResponseError.new(error_message(response))
111
+ end
112
+ end
113
+
114
+ def error_message(response)
115
+ message = "Request failed with error code #{response.code}"
116
+ response.nil? ? message : "#{message} and body: #{response.parsed_response}"
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,41 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+
3
+ module ITGlue
4
+ class Client
5
+ class Mapper
6
+ def self.map(raw_data)
7
+ self.new(raw_data).format
8
+ end
9
+
10
+ def initialize(raw_data)
11
+ @raw_data = raw_data
12
+ end
13
+
14
+ def format
15
+ collection? ? format_collection(@raw_data) : format_object(@raw_data)
16
+ end
17
+
18
+ private
19
+
20
+ def collection?
21
+ @raw_data.is_a?(Array)
22
+ end
23
+
24
+ def format_collection(data)
25
+ data.map { |d| format_object(d) }
26
+ end
27
+
28
+ def format_object(data)
29
+ {
30
+ id: data['id'].to_i,
31
+ type: data['type'],
32
+ attributes: transform_keys(data['attributes'])
33
+ }
34
+ end
35
+
36
+ def transform_keys(attributes)
37
+ attributes.map { |key, value| [key.underscore.to_sym, value] }.to_h
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,56 @@
1
+ module ITGlue
2
+ class Client
3
+ class PathProcessor
4
+ def self.process(asset_type, options = {})
5
+ self.new(asset_type, options).path
6
+ end
7
+
8
+ # @param asset_type [Symbol|String] the pluralized asset type name
9
+ # @param options [Hash] valid options:
10
+ # parent [ITGlue::Asset] the parent instance
11
+ # id [Integer] the asset id
12
+ def initialize(asset_type, options = {})
13
+ @asset_type = asset_type
14
+ @options = options
15
+ @path_array = []
16
+ end
17
+
18
+ def path
19
+ @path ||= path_array.unshift('').join('/')
20
+ end
21
+
22
+ private
23
+
24
+ def parent
25
+ @options[:parent]
26
+ end
27
+
28
+ def id
29
+ @options[:id]
30
+ end
31
+
32
+ def path_array
33
+ return @path_array if @processed
34
+ append_parent if parent
35
+ append_asset_type
36
+ append_id if id
37
+ @processed = true
38
+ @path_array
39
+ end
40
+
41
+ def append_parent
42
+ @path_array << parent.asset_type
43
+ @path_array << parent.id
44
+ @path_array << :relationships
45
+ end
46
+
47
+ def append_asset_type
48
+ @path_array << @asset_type
49
+ end
50
+
51
+ def append_id
52
+ @path_array << id
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module ITGlue
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itglue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Silva
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-05-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: httparty
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.16'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 0.15.7
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '0.16'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 0.15.7
75
+ - !ruby/object:Gem::Dependency
76
+ name: activesupport
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '5.2'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 3.0.0
85
+ type: :runtime
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '5.2'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 3.0.0
95
+ description: This gem provides a client for interactiong with the IT Glue API
96
+ email:
97
+ - berna.loyola@gmail.com
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - ".gitignore"
103
+ - ".rspec"
104
+ - ".travis.yml"
105
+ - Gemfile
106
+ - LICENSE.txt
107
+ - README.md
108
+ - Rakefile
109
+ - bin/console
110
+ - bin/setup
111
+ - itglue.gemspec
112
+ - lib/itglue.rb
113
+ - lib/itglue/asset.rb
114
+ - lib/itglue/asset/base.rb
115
+ - lib/itglue/asset/base/attributes.rb
116
+ - lib/itglue/asset/base/relatable.rb
117
+ - lib/itglue/asset/configuration.rb
118
+ - lib/itglue/asset/configuration_interface.rb
119
+ - lib/itglue/asset/configuration_status.rb
120
+ - lib/itglue/asset/configuration_type.rb
121
+ - lib/itglue/asset/organization.rb
122
+ - lib/itglue/client.rb
123
+ - lib/itglue/client/mapper.rb
124
+ - lib/itglue/client/path_processor.rb
125
+ - lib/itglue/version.rb
126
+ homepage: https://github.com/b-loyola/itglue
127
+ licenses:
128
+ - MIT
129
+ metadata: {}
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubyforge_project:
146
+ rubygems_version: 2.5.1
147
+ signing_key:
148
+ specification_version: 4
149
+ summary: A simple wrapper for the IT Glue API
150
+ test_files: []