afasgem 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +230 -0
- data/Rakefile +6 -0
- data/afasgem.gemspec +32 -0
- data/bin/connector_format.rb +177 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/afasgem.rb +46 -0
- data/lib/afasgem/configuration.rb +24 -0
- data/lib/afasgem/getconnector.rb +279 -0
- data/lib/afasgem/operators.rb +17 -0
- data/lib/afasgem/updateconnector.rb +91 -0
- data/lib/afasgem/version.rb +3 -0
- metadata +202 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c5bf46bef866cc1a2121ae0a52298e6beba6d9dd
|
4
|
+
data.tar.gz: 056bf5b73c04c3c8f03060763e5ea10e21b791b0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c14c4274605b912888249c0d08b0a8b3c35f60bdce9bfb012e9cfa2c81126807bab61822ee4f155e83bcaf7251bc4c1911528b6f0c664d54c214f4668087e30e
|
7
|
+
data.tar.gz: 72541628f918b44920f72e8613f171ecd1a0e456d83d1f25ff6240364a0980c91e29d341780ad350e1b1ecb4dc24ba92d6bad83aad1e907b56cf2abf92fe9be8
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Sprint ICT, Subhi Dweik
|
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,230 @@
|
|
1
|
+
# Afasgem
|
2
|
+
|
3
|
+
This very creatively named get wraps communication with AFAS get and updateconnectors
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'afasgem'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install afasgem
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### General config
|
24
|
+
|
25
|
+
This gem can be configured using the well known ruby configure block
|
26
|
+
|
27
|
+
```
|
28
|
+
# Start the config block
|
29
|
+
Afasgem.configuration do |config|
|
30
|
+
# The WSDL url of the AFAS getconnector
|
31
|
+
# Probable format: https://<Environment number>.afasonlineconnector.nl/ProfitServices/AppConnectorGet.asmx?WSDL
|
32
|
+
config.getconnector_url = 'getconnectorurl'
|
33
|
+
|
34
|
+
# The WSDL url of the AFAS updateconnector
|
35
|
+
# Probable format: https://<Environment number>.afasonlineconnector.nl/ProfitServices/AppConnectorUpdate.asmx?WSDL
|
36
|
+
config.updateconnector_url = 'updateconnectorurl'
|
37
|
+
|
38
|
+
# The WSDL url of the AFAS updateconnector
|
39
|
+
# Probable format: ?
|
40
|
+
config.dataconnector_url = 'dataconnectorurl'
|
41
|
+
|
42
|
+
# The token to use
|
43
|
+
config.token = 'token'
|
44
|
+
|
45
|
+
# The number of rows to fetch when not specified
|
46
|
+
config.default_results = 150
|
47
|
+
|
48
|
+
# Whether to log all requests to the console
|
49
|
+
config.debug = true
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
To start communicating with AFAS you need to construct a connector using the
|
54
|
+
`Afasgem.getconnector_factory` and `Afasgem.updateconnector_factory`. Both take
|
55
|
+
the connectorId (the name of the connector, for example `Profit_Debtor`) as an
|
56
|
+
argument
|
57
|
+
|
58
|
+
This will return a configured get or updateconnector instance that is ready to communicate.
|
59
|
+
|
60
|
+
### Getconnector
|
61
|
+
|
62
|
+
Create a getconnector using the factory after configuring afasgem
|
63
|
+
|
64
|
+
```
|
65
|
+
conn = Afasgem.getconnector_factory('Profit_Debtor')
|
66
|
+
```
|
67
|
+
|
68
|
+
#### Fetching data
|
69
|
+
|
70
|
+
The easiest way to get data out of a connector is to simply call `get_data`.
|
71
|
+
This will return an array of results, each in a hash. This hash will have the
|
72
|
+
AFAS field names as keys.
|
73
|
+
|
74
|
+
```
|
75
|
+
conn.get_data # [{result 1}, {result 2}]
|
76
|
+
```
|
77
|
+
|
78
|
+
The data xml is available using `get_data_xml`. This is the xml that contains
|
79
|
+
the data itself. Not the full SOAP request
|
80
|
+
|
81
|
+
`get_result` will return the full response as a hash. This also is not the full
|
82
|
+
SOAP request but just the interesting part of the response
|
83
|
+
|
84
|
+
When using `get_result`, `get_data`, or `get_data_xml`, the response
|
85
|
+
is cached and new requests will only be done when something was changed using
|
86
|
+
the pagination handlers below.
|
87
|
+
|
88
|
+
Calling `execute` issues a new request, even if nothing was changed
|
89
|
+
|
90
|
+
To get all data at once, the `get_all_results` method is available. This will
|
91
|
+
fetch all rows in a connector. Sadly there is no way to tell how many records
|
92
|
+
there are in total before fetching them all.
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
#### Handling pagination
|
97
|
+
|
98
|
+
```
|
99
|
+
conn.take(n) # Configures the connector to fetch n records at a time
|
100
|
+
conn.skip(n) # Configures the connector to skip the first n records
|
101
|
+
conn.page(n) # Provides a simple way to get the nth page of results, 1 indexed
|
102
|
+
conn.next # Gets the next page of results
|
103
|
+
conn.previous # Gets the previous page of results
|
104
|
+
```
|
105
|
+
|
106
|
+
All of the above methods provide fluent interfaced, meaning they can be chained.
|
107
|
+
|
108
|
+
```
|
109
|
+
# Will fetch result 15-25 since we are fetching 10 results a page,
|
110
|
+
# skipping the first 5 and then going to page 2
|
111
|
+
conn.take(10).skip(5).next.get_data
|
112
|
+
```
|
113
|
+
|
114
|
+
#### Filtering
|
115
|
+
|
116
|
+
This gem also wraps the filter functionality of the AFAS api. When adding a filter it is added with an and respective to the filters already in place. To filter using an OR you have to explicitly call `add_or`
|
117
|
+
|
118
|
+
```
|
119
|
+
# Filter where Field == 'val'
|
120
|
+
conn.add_filter('Field', FilterOperators::EQUAL, 'val')
|
121
|
+
|
122
|
+
# Filter where Field == 'val' && Field2 == 'val2'
|
123
|
+
conn.add_filter('Field', FilterOperators::EQUAL, 'val')
|
124
|
+
.add_filter('Field2', FilterOperators::EQUAL, 'val2')
|
125
|
+
|
126
|
+
# Filter where Field == 'val' || Field2 == 'val2'
|
127
|
+
conn.add_filter('Field', FilterOperators::EQUAL, 'val')
|
128
|
+
.add_or
|
129
|
+
.add_filter('Field2', FilterOperators::EQUAL, 'val2')
|
130
|
+
|
131
|
+
# Filter where (Field == 'val' && Field2 == 'val2') || (Field3 == 'val3')
|
132
|
+
conn.add_filter('Field', FilterOperators::EQUAL, 'val')
|
133
|
+
.add_filter('Field2', FilterOperators::EQUAL, 'val2')
|
134
|
+
.add_or
|
135
|
+
.add_filter('Field3', FilterOperators::EQUAL, 'val3')
|
136
|
+
```
|
137
|
+
|
138
|
+
To clear the filters in place use `clear_filters`
|
139
|
+
|
140
|
+
Available operators:
|
141
|
+
```
|
142
|
+
EQUAL # Value is exactly equal
|
143
|
+
LARGER_OR_EQUAL # Value is larger than or equal
|
144
|
+
SMALLER_OR_EQUAL # Value is smaller than or equal
|
145
|
+
LARGER_THAN # Value is larger than
|
146
|
+
SMALLER_THAN # Value is smaller than
|
147
|
+
LIKE # Text contains value
|
148
|
+
NOT_EQUAL # Value is not equal
|
149
|
+
EMPTY # Field is null
|
150
|
+
NOT_EMPTY # Field is not null
|
151
|
+
STARTS_WITH # Text starts with
|
152
|
+
NOT_LIKE # Text does not contain
|
153
|
+
NOT_STARTS_WITH # Text does not start with
|
154
|
+
ENDS_WITH # Text ends with
|
155
|
+
NOT_ENDS_WITH # Text does not end with
|
156
|
+
```
|
157
|
+
|
158
|
+
## Updateconnector data
|
159
|
+
|
160
|
+
To view the fields an updateconnector accepts, there is `bin/connector_format`. This script takes a few params and then lists the fields the passed updateconnector would accept
|
161
|
+
|
162
|
+
```
|
163
|
+
Usage: connector_format [options]
|
164
|
+
-u, --username NAME AFAS username
|
165
|
+
-p, --password PASSWORD AFAS password
|
166
|
+
-c, --connector CONNECTOR Name of the UpdateConnector
|
167
|
+
-e, --environment ENVIRONMENT Name of the environment
|
168
|
+
-h, --help Show this message
|
169
|
+
```
|
170
|
+
|
171
|
+
## Updateconnector
|
172
|
+
|
173
|
+
To Actually write data to the AFAS api you can use the `updateconnector_factory`. This factory will return an `UpdateConnector` object that has the following methods:
|
174
|
+
```
|
175
|
+
# Create a connector for the FbItemArticle updateconnector
|
176
|
+
connector = Afasgem.updateconnector_factory('FbItemArticle')
|
177
|
+
connector.insert(hash) # Insert data
|
178
|
+
connector.update(hash) # Update existing data
|
179
|
+
connector.delete(hash) # Delete existing data
|
180
|
+
```
|
181
|
+
|
182
|
+
The methods all take a hash that represents the object. Keys in this hash are expected to be fieldnames, while their values are treated like the field's values.
|
183
|
+
|
184
|
+
```
|
185
|
+
hash = { A: 'b', C: 5 } # => <A>b</A><C>5</C>
|
186
|
+
```
|
187
|
+
|
188
|
+
The wrapping xml is inferred using the updateconnector name and some constrant data.
|
189
|
+
|
190
|
+
Some objects accept nested objects as well as the usual fields. Those should be stored in the Objects key of the passed hash.
|
191
|
+
|
192
|
+
```
|
193
|
+
# <A>b</A><C>5</C>
|
194
|
+
# <Objects>
|
195
|
+
# <X>
|
196
|
+
# <Element>
|
197
|
+
# <Fields action='someaction'>
|
198
|
+
# <D>1</D>
|
199
|
+
# <E>2</E>
|
200
|
+
# </Fields>
|
201
|
+
# </Element>
|
202
|
+
# </X>
|
203
|
+
# <Y>
|
204
|
+
# <Element>
|
205
|
+
# <Fields action='someaction'>
|
206
|
+
# <F>3</F>
|
207
|
+
# <G>4</G>
|
208
|
+
# </Fields>
|
209
|
+
# </Element>
|
210
|
+
# </Y>
|
211
|
+
# </Objects>
|
212
|
+
# etc...
|
213
|
+
hash = { A: 'b', C: 5, Objects: { X: { D: 1, E: 2}, Y: { F: 3, G: 4} }
|
214
|
+
```
|
215
|
+
|
216
|
+
## Development
|
217
|
+
|
218
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
219
|
+
|
220
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
221
|
+
|
222
|
+
## Contributing
|
223
|
+
|
224
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Bonemind/Afasgem.
|
225
|
+
|
226
|
+
|
227
|
+
## License
|
228
|
+
|
229
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
230
|
+
|
data/Rakefile
ADDED
data/afasgem.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'afasgem/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "afasgem"
|
8
|
+
spec.version = Afasgem::VERSION
|
9
|
+
spec.authors = ["Subhi Dweik"]
|
10
|
+
spec.email = ["subhime@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A gem that wraps basic afas api functionality}
|
13
|
+
spec.homepage = "https://github.com/Bonemind/Afasgem"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'savon', '>= 2.11.1'
|
22
|
+
spec.add_dependency 'httpclient'
|
23
|
+
spec.add_dependency 'rubyntlm', '~> 0.3.2'
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency 'pry'
|
29
|
+
spec.add_development_dependency 'pry-nav'
|
30
|
+
spec.add_development_dependency 'pry-stack_explorer'
|
31
|
+
spec.add_development_dependency 'pry-doc'
|
32
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'savon'
|
2
|
+
require 'pp'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
# Parse xml to a hash
|
6
|
+
def from_xml(xml_io)
|
7
|
+
begin
|
8
|
+
result = Nokogiri::XML(xml_io)
|
9
|
+
return { result.root.name.to_sym => xml_node_to_hash(result.root)}
|
10
|
+
rescue Exception => e
|
11
|
+
puts e.backtrace
|
12
|
+
raise
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Parse each node to a hash
|
17
|
+
def xml_node_to_hash(node)
|
18
|
+
# If we are at the root of the document, start the hash
|
19
|
+
if node.element?
|
20
|
+
result_hash = {}
|
21
|
+
if node.attributes != {}
|
22
|
+
attributes = {}
|
23
|
+
node.attributes.keys.each do |key|
|
24
|
+
attributes[node.attributes[key].name.to_sym] = node.attributes[key].value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
if node.children.size > 0
|
28
|
+
node.children.each do |child|
|
29
|
+
result = xml_node_to_hash(child)
|
30
|
+
|
31
|
+
if child.name == "text"
|
32
|
+
unless child.next_sibling || child.previous_sibling
|
33
|
+
return result unless attributes
|
34
|
+
result_hash[child.name.to_sym] = result
|
35
|
+
end
|
36
|
+
elsif result_hash[child.name.to_sym]
|
37
|
+
|
38
|
+
if result_hash[child.name.to_sym].is_a?(Object::Array)
|
39
|
+
result_hash[child.name.to_sym] << result
|
40
|
+
else
|
41
|
+
result_hash[child.name.to_sym] = [result_hash[child.name.to_sym]] << result
|
42
|
+
end
|
43
|
+
else
|
44
|
+
result_hash[child.name.to_sym] = result
|
45
|
+
end
|
46
|
+
end
|
47
|
+
if attributes
|
48
|
+
#add code to remove non-data attributes e.g. xml schema, namespace here
|
49
|
+
#if there is a collision then node content supersets attributes
|
50
|
+
result_hash = attributes.merge(result_hash)
|
51
|
+
end
|
52
|
+
return result_hash
|
53
|
+
else
|
54
|
+
return attributes
|
55
|
+
end
|
56
|
+
else
|
57
|
+
return node.content.to_s
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# The dataconnector url, will probably not need to change
|
63
|
+
dataconnector_url = 'https://profitweb.afasonline.nl/profitservices/DataConnector.asmx?WSDL'
|
64
|
+
|
65
|
+
# The username to use
|
66
|
+
username = nil
|
67
|
+
|
68
|
+
# The password to use
|
69
|
+
password = nil
|
70
|
+
|
71
|
+
# The connector we want a description of
|
72
|
+
connector_name = nil
|
73
|
+
|
74
|
+
# The AFAS environment, probably in the format: 'X12345XX'
|
75
|
+
environment_id = nil
|
76
|
+
|
77
|
+
# Create an optionparser
|
78
|
+
OptionParser.new do |opts|
|
79
|
+
# Set username
|
80
|
+
opts.on('-u', '--username NAME', 'AFAS username') { |v| username = v }
|
81
|
+
|
82
|
+
# Set password
|
83
|
+
opts.on('-p', '--password PASSWORD', 'AFAS password') { |v| password = v }
|
84
|
+
|
85
|
+
# Set connector name
|
86
|
+
opts.on('-c', '--connector CONNECTOR', 'Name of the UpdateConnector') { |v| connector_name = v }
|
87
|
+
|
88
|
+
# Set environment
|
89
|
+
opts.on('-e', '--environment ENVIRONMENT', 'Name of the environment') { |v| environment_id = v }
|
90
|
+
|
91
|
+
# Display help
|
92
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
93
|
+
puts opts
|
94
|
+
exit
|
95
|
+
end
|
96
|
+
# Parse
|
97
|
+
end.parse!
|
98
|
+
|
99
|
+
# All params are required, fail is one is missing
|
100
|
+
fail ArgumentError.new('Username is required') unless username
|
101
|
+
fail ArgumentError.new('Password is required') unless password
|
102
|
+
fail ArgumentError.new('Connector name is required') unless connector_name
|
103
|
+
fail ArgumentError.new('Environment name is required') unless environment_id
|
104
|
+
|
105
|
+
# Setup Savon with the credentials the user supplied
|
106
|
+
client = Savon.client(wsdl: dataconnector_url, basic_auth: [username, password])
|
107
|
+
resp = client.call(:execute, {
|
108
|
+
message: {
|
109
|
+
environmentId: environment_id,
|
110
|
+
userId: username,
|
111
|
+
password: password,
|
112
|
+
dataID: 'GetXmlSchema',
|
113
|
+
parametersXml: "<Parameters><UpdateConnectorId>#{connector_name}</UpdateConnectorId></Parameters>"
|
114
|
+
}
|
115
|
+
})
|
116
|
+
|
117
|
+
# Get response xml out of wrapper
|
118
|
+
xml = resp.hash[:envelope][:body][:execute_response][:execute_result]
|
119
|
+
|
120
|
+
|
121
|
+
# Get the schema xml out of the response
|
122
|
+
schemaxml = from_xml(xml)[:AfasDataConnector][:ConnectorData][:Schema]
|
123
|
+
|
124
|
+
# Parse it ignoring namespaces. This because we only need the data and will not construct responses from the data
|
125
|
+
schema = Nokogiri::XML(schemaxml).remove_namespaces!
|
126
|
+
|
127
|
+
# Xpath to get the fields array of the main object
|
128
|
+
main_object_xpath = '//*[@name="Fields" and not(ancestor::*[@name="Objects"])]'
|
129
|
+
|
130
|
+
# Xpath to get the nested objects
|
131
|
+
nested_objects_xpath = '//*[@name="Objects"]/complexType/sequence/*'
|
132
|
+
|
133
|
+
# Xpath to get the fields of the nested objects
|
134
|
+
nested_objects_fields_xpath = '*//*[@name="Fields"]/complexType/sequence'
|
135
|
+
|
136
|
+
|
137
|
+
# Array of properties of the main object, contains comment and xml element alternating
|
138
|
+
main = schema.xpath(main_object_xpath)[0].children.children.children
|
139
|
+
nested = schema.xpath(nested_objects_xpath)
|
140
|
+
|
141
|
+
# Prints the fields in a field array
|
142
|
+
def print_fields(field_array)
|
143
|
+
field_array.each do |el|
|
144
|
+
if el.is_a?(Nokogiri::XML::Comment)
|
145
|
+
puts '-' * 80
|
146
|
+
puts el
|
147
|
+
end
|
148
|
+
if el.is_a?(Nokogiri::XML::Element)
|
149
|
+
puts el.attributes['name'].value
|
150
|
+
puts 'Optional' if el.attributes['nillable']
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Output the main connector name
|
156
|
+
puts '*' * 8
|
157
|
+
puts connector_name
|
158
|
+
puts '*' * 80
|
159
|
+
|
160
|
+
# Output the fields of the main object
|
161
|
+
print_fields(main)
|
162
|
+
|
163
|
+
# Iterate over nested objects
|
164
|
+
nested.each do |el|
|
165
|
+
|
166
|
+
# PRint the name of the nested object
|
167
|
+
puts '=' * 80
|
168
|
+
puts el.attributes['name'].value
|
169
|
+
puts '=' * 80
|
170
|
+
|
171
|
+
# Get the fields for this object
|
172
|
+
fields = el.xpath(nested_objects_fields_xpath).children
|
173
|
+
|
174
|
+
# Print the fields for this object
|
175
|
+
print_fields(fields)
|
176
|
+
end
|
177
|
+
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "afasgem"
|
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
|
data/bin/setup
ADDED
data/lib/afasgem.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "afasgem/version"
|
2
|
+
require 'afasgem/configuration'
|
3
|
+
require 'afasgem/getconnector'
|
4
|
+
require 'afasgem/updateconnector'
|
5
|
+
require 'afasgem/operators'
|
6
|
+
require 'savon'
|
7
|
+
require 'nokogiri'
|
8
|
+
|
9
|
+
module Afasgem
|
10
|
+
# Make the gem configurable
|
11
|
+
# See afasgem/configuration.rb for code origin
|
12
|
+
extend Configuration
|
13
|
+
|
14
|
+
# The WSDL url of the getconnector
|
15
|
+
define_setting :getconnector_url
|
16
|
+
|
17
|
+
# The WSDL url of the updateconnector
|
18
|
+
define_setting :updateconnector_url
|
19
|
+
|
20
|
+
# The WSDL url of the dataconnector
|
21
|
+
define_setting :dataconnector_url
|
22
|
+
# The token, this is only the actual token, not the whole xml thing
|
23
|
+
define_setting :token
|
24
|
+
|
25
|
+
|
26
|
+
# The number of results to request by default
|
27
|
+
define_setting :default_results, 100
|
28
|
+
|
29
|
+
# Defines whether the requests and responses should be printed
|
30
|
+
define_setting :debug, false
|
31
|
+
|
32
|
+
# Constructs a getconnect for the passed connector name
|
33
|
+
def self.getconnector_factory(name)
|
34
|
+
return GetConnector.new(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Constructs an updateconnector for the passed connector name
|
38
|
+
def self.updateconnector_factory(name)
|
39
|
+
return UpdateConnector.new(name)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Builds the token xml from the configured token
|
43
|
+
def self.get_token
|
44
|
+
return "<token><version>1</version><data>#{Afasgem::token}</data></token>"
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Provides module configuration
|
2
|
+
# # Source: https://viget.com/extend/easy-gem-configuration-variables-with-defaults
|
3
|
+
module Configuration
|
4
|
+
def configuration
|
5
|
+
yield self
|
6
|
+
end
|
7
|
+
|
8
|
+
def define_setting(name, default = nil)
|
9
|
+
class_variable_set("@@#{name}", default)
|
10
|
+
define_class_method "#{name}=" do |value|
|
11
|
+
class_variable_set("@@#{name}", value)
|
12
|
+
end
|
13
|
+
define_class_method name do
|
14
|
+
class_variable_get("@@#{name}")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def define_class_method(name, &block)
|
20
|
+
(class << self; self; end).instance_eval do
|
21
|
+
define_method name, &block
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
# Implements communication with getconnectors
|
2
|
+
class GetConnector
|
3
|
+
|
4
|
+
# Constructor, takes the name of the connector
|
5
|
+
def initialize(name)
|
6
|
+
@connectorname = name
|
7
|
+
@filters = []
|
8
|
+
if Afasgem::debug
|
9
|
+
# Build a debug client if the debug flag is set
|
10
|
+
@client = Savon.client(
|
11
|
+
wsdl: Afasgem::getconnector_url,
|
12
|
+
log: true,
|
13
|
+
log_level: :debug,
|
14
|
+
pretty_print_xml: true
|
15
|
+
)
|
16
|
+
else
|
17
|
+
# Build a normal client otherwise
|
18
|
+
@client = Savon.client(wsdl: Afasgem::getconnector_url)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Set the number of results we want to have
|
23
|
+
# Provides a fluent interface
|
24
|
+
def take(count)
|
25
|
+
fail ArgumentError.new("Count cannot be lower than 1, #{count} given") unless count > 0
|
26
|
+
@result = nil
|
27
|
+
@resultcount = count
|
28
|
+
return self
|
29
|
+
end
|
30
|
+
|
31
|
+
# Set the number of results we want to skip
|
32
|
+
# Provides a fluent interface
|
33
|
+
def skip(count)
|
34
|
+
fail ArgumentError.new("Count cannot be lower than 1, #{count} given") unless count > 0
|
35
|
+
@result = nil
|
36
|
+
@skip = count
|
37
|
+
return self
|
38
|
+
end
|
39
|
+
|
40
|
+
# Set the page we want to fetch
|
41
|
+
# 1 indexed (i.e. page 1 will fetch result 0 to x)
|
42
|
+
# Provides a fluent interface
|
43
|
+
def page(number)
|
44
|
+
fail ArgumentError.new("Page number cannot be lower than 1, #{number} given") unless number > 0
|
45
|
+
@result = nil
|
46
|
+
@skip = (number - 1) * get_resultcount
|
47
|
+
return self
|
48
|
+
end
|
49
|
+
|
50
|
+
# Fetch the next page
|
51
|
+
# Provides a fluent interface
|
52
|
+
def next
|
53
|
+
@skip = (@skip || 0) + get_resultcount
|
54
|
+
@result = nil
|
55
|
+
return self
|
56
|
+
end
|
57
|
+
|
58
|
+
# Fetch the previous page
|
59
|
+
# Provides a fluent interface
|
60
|
+
def previous
|
61
|
+
@result = nil
|
62
|
+
@skip = (@skip || 0) - get_resultcount
|
63
|
+
@skip = [0, @skip].max
|
64
|
+
return self
|
65
|
+
end
|
66
|
+
|
67
|
+
# execute the request
|
68
|
+
# Provides a fluent interface
|
69
|
+
def execute
|
70
|
+
result = execute_request(get_resultcount, @skip)
|
71
|
+
|
72
|
+
@data_xml = result[0]
|
73
|
+
@result = result[1]
|
74
|
+
return self
|
75
|
+
end
|
76
|
+
|
77
|
+
# Fetches all results
|
78
|
+
# Data is not cached
|
79
|
+
def get_all_results
|
80
|
+
result_array = []
|
81
|
+
skip = 0
|
82
|
+
take = 1000
|
83
|
+
loop do
|
84
|
+
current_result = get_data_from_result(execute_request(take, skip)[1])
|
85
|
+
result_array.concat(current_result)
|
86
|
+
skip = skip + take
|
87
|
+
break if current_result.size != take
|
88
|
+
end
|
89
|
+
return result_array
|
90
|
+
end
|
91
|
+
|
92
|
+
# Adds a filter to the current filter list
|
93
|
+
# Provides a fluent interface
|
94
|
+
def add_filter(field, operator, value = nil)
|
95
|
+
if @filters.size == 0
|
96
|
+
@filters.push([])
|
97
|
+
end
|
98
|
+
|
99
|
+
# Only the EMPTY and NOT_EMPTY filters should accept a nil value
|
100
|
+
if !value
|
101
|
+
unless operator == FilterOperators::EMPTY || operator == FilterOperators::NOT_EMPTY
|
102
|
+
raise ArgumentError.new('Value can only be empty when using FilterOperator::EMPTY or FilterOperator::NOT_EMPTY')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
@filters.last.push({field: field, operator: operator, value: value})
|
106
|
+
return self
|
107
|
+
end
|
108
|
+
|
109
|
+
# Adds an OR to the current filter list
|
110
|
+
# Provides a fluent interface
|
111
|
+
def add_or
|
112
|
+
@filters.push([]) if @filters.last && @filters.last.size > 0
|
113
|
+
return self
|
114
|
+
end
|
115
|
+
|
116
|
+
# Clears the filters in place
|
117
|
+
# Provides a fluent interface
|
118
|
+
def clear_filters
|
119
|
+
@filters = []
|
120
|
+
return self
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns the result as a hash
|
124
|
+
# This includes the type definition
|
125
|
+
def get_result
|
126
|
+
execute unless @result
|
127
|
+
return @result
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns the actual data as a hash
|
131
|
+
def get_data
|
132
|
+
execute unless @result
|
133
|
+
return get_data_from_result(@result)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns the raw xml
|
137
|
+
def get_data_xml
|
138
|
+
execute unless @data_xml
|
139
|
+
return @data_xml
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
# Actually fires the request
|
145
|
+
def execute_request(take, skip = nil)
|
146
|
+
message = {
|
147
|
+
token: Afasgem.get_token,
|
148
|
+
connectorId: @connectorname,
|
149
|
+
take: take
|
150
|
+
}
|
151
|
+
|
152
|
+
message[:skip] = skip if skip
|
153
|
+
filter_string = get_filter_string
|
154
|
+
message[:filtersXml] = filter_string if filter_string
|
155
|
+
|
156
|
+
resp = @client.call(:get_data, message: message)
|
157
|
+
xml_string = resp.hash[:envelope][:body][:get_data_response][:get_data_result]
|
158
|
+
return [xml_string, from_xml(xml_string)]
|
159
|
+
end
|
160
|
+
|
161
|
+
# Returns the filter xml in string format
|
162
|
+
def get_filter_string
|
163
|
+
return nil if @filters.size == 0
|
164
|
+
filters = []
|
165
|
+
|
166
|
+
# Loop over each filtergroup
|
167
|
+
# All conditions in a filtergroup are combined using AND
|
168
|
+
# All filtergroups are combined using OR
|
169
|
+
@filters.each_with_index do |filter, index|
|
170
|
+
fields = []
|
171
|
+
|
172
|
+
# Loop over all conditions in a filter group
|
173
|
+
filter.each do |condition|
|
174
|
+
field = condition[:field]
|
175
|
+
operator = condition[:operator]
|
176
|
+
value = condition[:value]
|
177
|
+
|
178
|
+
# Some filters operate on strings and need wildcards
|
179
|
+
# Transform value if needed
|
180
|
+
case operator
|
181
|
+
when FilterOperators::LIKE
|
182
|
+
value = "%#{value}%"
|
183
|
+
when FilterOperators::STARTS_WITH
|
184
|
+
value = "#{value}%"
|
185
|
+
when FilterOperators::NOT_LIKE
|
186
|
+
value = "%#{value}%"
|
187
|
+
when FilterOperators::NOT_STARTS_WITH
|
188
|
+
value = "#{value}%"
|
189
|
+
when FilterOperators::ENDS_WITH
|
190
|
+
value = "%#{value}"
|
191
|
+
when FilterOperators::NOT_ENDS_WITH
|
192
|
+
value = "%#{value}"
|
193
|
+
when FilterOperators::EMPTY
|
194
|
+
# EMPTY and NOT_EMPTY operators require the filter to be in a different format
|
195
|
+
# This because they take no value
|
196
|
+
fields.push("<Field FieldId=\"#{field}\" OperatorType=\"#{operator}\" />")
|
197
|
+
next
|
198
|
+
when FilterOperators::NOT_EMPTY
|
199
|
+
fields.push("<Field FieldId=\"#{field}\" OperatorType=\"#{operator}\" />")
|
200
|
+
next
|
201
|
+
end
|
202
|
+
|
203
|
+
# Add this filterstring to filters
|
204
|
+
fields.push("<Field FieldId=\"#{field}\" OperatorType=\"#{operator}\">#{value}</Field>")
|
205
|
+
end
|
206
|
+
|
207
|
+
# Make sure all filtergroups are OR'ed and add them
|
208
|
+
filters.push("<Filter FilterId=\"Filter #{index}\">#{fields.join}</Filter>")
|
209
|
+
end
|
210
|
+
|
211
|
+
# Return the whole filterstring
|
212
|
+
return "<Filters>#{filters.join}</Filters>"
|
213
|
+
end
|
214
|
+
|
215
|
+
# Returns the number of results we want to fetch
|
216
|
+
def get_resultcount
|
217
|
+
return @resultcount || Afasgem.default_results
|
218
|
+
end
|
219
|
+
|
220
|
+
# Returns the actual rows from a parsed response hash
|
221
|
+
def get_data_from_result(result)
|
222
|
+
return result[:AfasGetConnector][@connectorname.to_sym] || []
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
# Source of code below: https://gist.github.com/huy/819999
|
227
|
+
def from_xml(xml_io)
|
228
|
+
begin
|
229
|
+
result = Nokogiri::XML(xml_io)
|
230
|
+
return { result.root.name.to_sym => xml_node_to_hash(result.root)}
|
231
|
+
rescue Exception => e
|
232
|
+
# raise your custom exception here
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def xml_node_to_hash(node)
|
237
|
+
# If we are at the root of the document, start the hash
|
238
|
+
if node.element?
|
239
|
+
result_hash = {}
|
240
|
+
if node.attributes != {}
|
241
|
+
attributes = {}
|
242
|
+
node.attributes.keys.each do |key|
|
243
|
+
attributes[node.attributes[key].name.to_sym] = node.attributes[key].value
|
244
|
+
end
|
245
|
+
end
|
246
|
+
if node.children.size > 0
|
247
|
+
node.children.each do |child|
|
248
|
+
result = xml_node_to_hash(child)
|
249
|
+
|
250
|
+
if child.name == "text"
|
251
|
+
unless child.next_sibling || child.previous_sibling
|
252
|
+
return result unless attributes
|
253
|
+
result_hash[child.name.to_sym] = result
|
254
|
+
end
|
255
|
+
elsif result_hash[child.name.to_sym]
|
256
|
+
|
257
|
+
if result_hash[child.name.to_sym].is_a?(Object::Array)
|
258
|
+
result_hash[child.name.to_sym] << result
|
259
|
+
else
|
260
|
+
result_hash[child.name.to_sym] = [result_hash[child.name.to_sym]] << result
|
261
|
+
end
|
262
|
+
else
|
263
|
+
result_hash[child.name.to_sym] = result
|
264
|
+
end
|
265
|
+
end
|
266
|
+
if attributes
|
267
|
+
#add code to remove non-data attributes e.g. xml schema, namespace here
|
268
|
+
#if there is a collision then node content supersets attributes
|
269
|
+
result_hash = attributes.merge(result_hash)
|
270
|
+
end
|
271
|
+
return result_hash
|
272
|
+
else
|
273
|
+
return attributes
|
274
|
+
end
|
275
|
+
else
|
276
|
+
return node.content.to_s
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# This module maps constants to AFAS filter ints
|
2
|
+
module FilterOperators
|
3
|
+
EQUAL = 1
|
4
|
+
LARGER_OR_EQUAL = 2
|
5
|
+
SMALLER_OR_EQUAL = 3
|
6
|
+
LARGER_THAN = 4
|
7
|
+
SMALLER_THAN = 5
|
8
|
+
LIKE = 6
|
9
|
+
NOT_EQUAL = 7
|
10
|
+
EMPTY = 8
|
11
|
+
NOT_EMPTY = 9
|
12
|
+
STARTS_WITH = 10
|
13
|
+
NOT_LIKE = 11
|
14
|
+
NOT_STARTS_WITH = 12
|
15
|
+
ENDS_WITH = 13
|
16
|
+
NOT_ENDS_WITH = 14
|
17
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
class UpdateConnector
|
2
|
+
|
3
|
+
# Constructor, takes the connector name
|
4
|
+
def initialize(name)
|
5
|
+
@connectorname = name
|
6
|
+
if Afasgem::debug
|
7
|
+
# Build a debug client if the debug flag is set
|
8
|
+
@client = Savon.client(
|
9
|
+
wsdl: Afasgem::updateconnector_url,
|
10
|
+
log: true,
|
11
|
+
log_level: :debug,
|
12
|
+
pretty_print_xml: true
|
13
|
+
)
|
14
|
+
else
|
15
|
+
# Build a normal client otherwise
|
16
|
+
@client = Savon.client(wsdl: Afasgem::updateconnector_url)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Method to return the savon client for this constructor
|
21
|
+
def client
|
22
|
+
return @client
|
23
|
+
end
|
24
|
+
|
25
|
+
# Executes an insert action using the passed object hash
|
26
|
+
def insert(objecthash)
|
27
|
+
xml = build_xml(objecthash, 'insert')
|
28
|
+
return execute(xml)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Executes an update action using the passed object hash
|
32
|
+
def update(objecthash)
|
33
|
+
xml = build_xml(objecthash, 'update')
|
34
|
+
return execute(xml)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Executes a delete action using the passed object hash
|
38
|
+
def delete(objecthash)
|
39
|
+
xml = build_xml(objecthash, 'delete')
|
40
|
+
return execute(xml)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Builds the inner xml to send to the afas api from the passed hash and action
|
46
|
+
def build_xml(objecthash, action)
|
47
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
48
|
+
xml.send(@connectorname.to_sym, 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance") {
|
49
|
+
xml.Element {
|
50
|
+
xml.Fields(Action: action) {
|
51
|
+
objecthash.each do |k, v|
|
52
|
+
xml.send(k.to_sym, v) unless k.to_s == 'Objects'
|
53
|
+
build_nested_xml(xml, v, action) if k.to_s == 'Objects'
|
54
|
+
end
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
end
|
59
|
+
return builder.to_xml.to_s
|
60
|
+
end
|
61
|
+
|
62
|
+
# Builds the xml for nested objects
|
63
|
+
def build_nested_xml(xml, objects, action)
|
64
|
+
xml.Objects {
|
65
|
+
objects.each do |obj, values|
|
66
|
+
|
67
|
+
xml.send(obj) {
|
68
|
+
xml.Element {
|
69
|
+
xml.Fields(Action: action) {
|
70
|
+
values.each do |k, v|
|
71
|
+
xml.send(k, v)
|
72
|
+
end
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
end
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
# Actually calls the afas api
|
81
|
+
def execute(xml)
|
82
|
+
message = {
|
83
|
+
token: Afasgem.get_token,
|
84
|
+
connectorType: @connectorname,
|
85
|
+
connectorVersion: 1,
|
86
|
+
dataXml: xml
|
87
|
+
}
|
88
|
+
resp = @client.call(:execute, message: message)
|
89
|
+
return resp
|
90
|
+
end
|
91
|
+
end
|
metadata
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: afasgem
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Subhi Dweik
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: savon
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.11.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.11.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: httpclient
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubyntlm
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.3.2
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.3.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.10'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.10'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry-nav
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
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
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: pry-stack_explorer
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: pry-doc
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description:
|
154
|
+
email:
|
155
|
+
- subhime@gmail.com
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- ".gitignore"
|
161
|
+
- ".rspec"
|
162
|
+
- ".travis.yml"
|
163
|
+
- Gemfile
|
164
|
+
- LICENSE.txt
|
165
|
+
- README.md
|
166
|
+
- Rakefile
|
167
|
+
- afasgem.gemspec
|
168
|
+
- bin/connector_format.rb
|
169
|
+
- bin/console
|
170
|
+
- bin/setup
|
171
|
+
- lib/afasgem.rb
|
172
|
+
- lib/afasgem/configuration.rb
|
173
|
+
- lib/afasgem/getconnector.rb
|
174
|
+
- lib/afasgem/operators.rb
|
175
|
+
- lib/afasgem/updateconnector.rb
|
176
|
+
- lib/afasgem/version.rb
|
177
|
+
homepage: https://github.com/Bonemind/Afasgem
|
178
|
+
licenses:
|
179
|
+
- MIT
|
180
|
+
metadata: {}
|
181
|
+
post_install_message:
|
182
|
+
rdoc_options: []
|
183
|
+
require_paths:
|
184
|
+
- lib
|
185
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
requirements: []
|
196
|
+
rubyforge_project:
|
197
|
+
rubygems_version: 2.4.8
|
198
|
+
signing_key:
|
199
|
+
specification_version: 4
|
200
|
+
summary: A gem that wraps basic afas api functionality
|
201
|
+
test_files: []
|
202
|
+
has_rdoc:
|