projector_pws 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: 45d785b1f6f1ff2701b369ef782874d78c1205c2
4
+ data.tar.gz: d09550953bff128a3ab30daf083a5e91af78ac01
5
+ SHA512:
6
+ metadata.gz: dd771285d83de784fecd46c54ee9ba749c53a899b9ac097c4d285a45a3b3c45b01c33a0538dad3e0d8c6af99f919b5348c7c04f35d71dce93e9ba594103554ee
7
+ data.tar.gz: 7e414dfbaaab808c0a984b1c4e76c144e616348a6a0e5b10f729c9c3db95e54a7f745ae0f80eca76246c2448bd39b7651ab6cf36efe953e024c38017fb97fc00
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .idea
2
+ Gemfile.lock
3
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Paul Duncan
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,213 @@
1
+ # ProjectorPWS
2
+
3
+ Client library for accessing Projector PSA\'s Web Services (PWS)
4
+
5
+ ## Presentation
6
+
7
+ This library provides access to Projector PSA\'s Web Services (PWS).
8
+
9
+ ## Installation
10
+
11
+ ### Gemfile
12
+ ```ruby
13
+ gem 'projector_pws'
14
+ ```
15
+
16
+ ### Terminal
17
+ ```bash
18
+ gem install -V projector_pws
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### Symbolize Keys
24
+
25
+ A _sym_keys_ method is monkey-patched into the *Array* and *Hash* classes, and provides a way to recursively convert *keys* to *symbols*.
26
+ This is mostly useful when loading Hashes from external resources (YAML, CSV, JSON, etc...), where keys will be stored as strings.
27
+
28
+ ```ruby
29
+ a = { 'foo' => 'bar', 'nested' => [{ 'problems' => 'none' }] }
30
+ a.sym_keys
31
+ # => {:foo=>"bar", :nested=>[{:problems=>"none"}]}
32
+ ```
33
+
34
+ ### Deep-clone
35
+
36
+ A _dclone_ method is monkey-patched into the *Array* and *Hash* classes, and provides a way to recursively *deep-clone* an instance.
37
+
38
+ ```ruby
39
+ a = { foo: 'bar', bar: :kill_me, nested: [{ problems: 'none' }] }
40
+ b = a.dclone
41
+ b[:nested] << :foo
42
+ b[:nested][:problems] = 'no way'
43
+ b[:test] = :bork
44
+ b[:foo] = nil
45
+ b.delete :bar
46
+ a
47
+ # => {:foo=>nil, :nested=>[{:problems=>"no way"}, :foo], :test => :bork}
48
+ b
49
+ # => {:foo=>"bar", :nested=>[{:problems=>"none"}]}
50
+ ```
51
+
52
+ ### Right/Left Padding
53
+
54
+ Two padding methods _rpad_ and _lpad_ are monkey-patched into the *String* class, and provide a way to pad any string to a given length using a given filler string.
55
+
56
+ ```ruby
57
+ a = 'foo'
58
+ a.rpad 10
59
+ # => "foo "
60
+ a.rpad 10, '-'
61
+ # => "foo-------"
62
+ a.rpad 2, '-'
63
+ # => "fo"
64
+ a.lpad 10
65
+ # => " foo"
66
+ a.lpad 10, '-'
67
+ # => "-------foo"
68
+ a.rpad 2, '-'
69
+ # => "oo"
70
+ ```
71
+
72
+ ### Object Try (Undefined Method Call)
73
+
74
+ A _try_ method is monkey-patched into the *Object* root class, providing a means to call undefined methods on objects without raising anything (returning *nil* instead).
75
+
76
+ ```ruby
77
+ 'foobar'.try :foo
78
+ # => nil
79
+ 32.try :to_s
80
+ # => '32'
81
+ 32.try :+, 3
82
+ # => 35
83
+ ['foo', 'bar'].try(:collect) { |e| "-#{e}-" }
84
+ # => ['-foo-', '-bar-']
85
+ ```
86
+
87
+ ### Get Non-Empty String
88
+
89
+ A _nstr_ method is monkey-patched into the *String* class. This method returns nil when the String is empty, the String otherwise.
90
+
91
+ ```ruby
92
+ ''.nstr
93
+ # => nil
94
+ 'foo'.nstr
95
+ # => 'foo'
96
+ nil.try :nstr
97
+ # => nil
98
+ 'bar'.try :nstr
99
+ # => 'bar'
100
+ ```
101
+
102
+ ### String Case Conversions
103
+
104
+ Case-conversion methods are monkey-patched into the *String* class. The following methods are made available:
105
+ * camelcase ('foo-bar' => 'FooBar')
106
+ * snakecase ('FooBar' => 'foo-bar')
107
+ * kebabcase ('FooBar' => 'foo_bar')
108
+
109
+ ```ruby
110
+ 'foo_bar'.camelcase
111
+ # => 'FooBar'
112
+ 'foo-bar'.camelcase
113
+ # => 'FooBar'
114
+
115
+ 'FooBar'.snakecase
116
+ # => 'foo-bar'
117
+ 'foo_bar'.snakecase
118
+ # => 'foo-bar'
119
+
120
+ 'FooBar'.kebabcase
121
+ # => 'foo_bar'
122
+ 'foo-bar'.kebabcase
123
+ # => 'foo_bar'
124
+ ```
125
+
126
+ ### Module utilities
127
+
128
+ #### Get Module Name
129
+
130
+ A _mod_name_ method is monkey-patched into the *Module* class. This allows obtaining the name of any module, without its hierarchical tree.
131
+
132
+ ```ruby
133
+ module Foo
134
+ module Bar
135
+ end
136
+ end
137
+
138
+ Foo.name
139
+ # => 'Foo'
140
+
141
+ Foo.mod_name
142
+ # => 'Foo'
143
+
144
+ Foo::Bar.name
145
+ # => 'Foo::Bar'
146
+
147
+ Foo::Bar.mod_name # <= This is where it gets interesting
148
+ # => 'Bar'
149
+ ```
150
+
151
+ #### Get Module Parent Name
152
+
153
+ A _mod_parent_name_ method is monkey-patched into the *Module* class. This allows obtaining the name of any module's parent.
154
+
155
+ ```ruby
156
+ module Foo
157
+ module Bar
158
+ module Test
159
+ end
160
+ end
161
+ end
162
+
163
+ Foo.mod_parent_name
164
+ # => ''
165
+
166
+ Foo::Bar.mod_parent_name
167
+ # => 'Foo'
168
+
169
+ Foo::Bar::Test.mod_parent_name
170
+ # => 'Foo::Bar'
171
+ ```
172
+
173
+ #### Get Module Parent
174
+
175
+ A _mod_parent_ method is monkey-patched into the *Module* class. This allows obtaining any module's parent.
176
+
177
+ ```ruby
178
+ module Foo
179
+ module Bar
180
+ module Test
181
+ end
182
+ end
183
+ end
184
+
185
+ Foo.mod_parent
186
+ # => nil
187
+
188
+ Foo::Bar.mod_parent
189
+ # => Foo
190
+
191
+ Foo::Bar::Test.mod_parent_name
192
+ # => Foo::Bar
193
+ ```
194
+
195
+ ### Time Duration
196
+
197
+ A _duration_ method is monkey-patched into the 'Numeric' class. This method returns a textual string representation of the time duration.
198
+ An optional *elements* argument allows setting the maximum number of time-elements (days, hours, minutes, ...) to display.
199
+
200
+ ```ruby
201
+ 86400.duration
202
+ # => '1 Day'
203
+ ((3600 * 3) + 60 + 12).duration
204
+ # => '3 Hours 1 Minute 12 Seconds'
205
+ ((3600 * 3) + 60 + 12).duration 1
206
+ # => '3 Hours'
207
+ ((3600 * 3) + 60 + 12).duration 2
208
+ # => '3 Hours 1 Minute'
209
+ ```
210
+
211
+ ## License
212
+
213
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+ require 'bundler/gem_tasks'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.pattern = 'test/**/test*.rb'
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,9 @@
1
+ # ProjectorPWS
2
+ # by Eresse <eresse@eresse.net>
3
+
4
+ # ProjectorPWS Module
5
+ module ProjectorPWS
6
+
7
+ # Version
8
+ VERSION = '0.1.0'
9
+ end
@@ -0,0 +1,259 @@
1
+ # ProjectorPWS
2
+ # by Eresse <eresse@eresse.net>
3
+
4
+ # External Includes
5
+ require 'savon'
6
+ require 'aromat'
7
+
8
+ # Internal Includes
9
+ require 'projector_pws/version'
10
+
11
+ # ProjectorPWS Module:
12
+ # Root Module for ProjectorPWS.
13
+ module ProjectorPWS
14
+
15
+ # Service Definition
16
+ WSDL = 'https://secure.projectorpsa.com/OpsProjectorWcfSvc/PwsProjectorServices.svc?wsdl'
17
+
18
+ # Base URL
19
+ BASE_URL = 'https://secure.projectorpsa.com'
20
+
21
+ # URL Path
22
+ URL_PATH = 'OpsProjectorWcfSvc/PwsProjectorServices.svc'
23
+
24
+ # Namespaces
25
+ NAMESPACE = 'http://projectorpsa.com/PwsProjectorServices/'
26
+ EXTRA_NAMESPACES = {
27
+ 'xmlns:req' => 'http://projectorpsa.com/DataContracts/Requests/',
28
+ 'xmlns:tim' => 'http://projectorpsa.com/DataContracts/Shared/TimeAndCost/',
29
+ 'xmlns:com' => 'http://projectorpsa.com/DataContracts/Shared/Common/'
30
+ }
31
+
32
+ # Work Week
33
+ WEEK_START = :monday
34
+ WEEK_END = :friday
35
+
36
+ # Days Per Week
37
+ DAYS_PER_WEEK = 5
38
+
39
+ # Hours Per Day
40
+ HOURS_PER_DAY = 8
41
+
42
+ # Real Hours Per Day
43
+ HOURS_PER_DAY_REAL = 24
44
+
45
+ # Minutes Per Hour
46
+ MINUTES_PER_HOUR = 60
47
+
48
+ # Minutes Per Day
49
+ MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR
50
+
51
+ # Minutes Per Week
52
+ MINUTES_PER_WEEK = MINUTES_PER_DAY * DAYS_PER_WEEK
53
+
54
+ # Open Client
55
+ def self.open url = BASE_URL
56
+ c = Savon.client wsdl: WSDL, endpoint: service_url(url), namespace: NAMESPACE, env_namespace: :soapenv, namespace_identifier: :pws, namespaces: EXTRA_NAMESPACES
57
+ return yield c if block_given?
58
+ c
59
+ end
60
+
61
+ # Authenticate
62
+ def self.authenticate username, password, account_code = nil
63
+
64
+ # Prepare URLs
65
+ next_url = BASE_URL
66
+ last_url = ''
67
+
68
+ # Prepare Credentials
69
+ creds = {}
70
+ creds['req:AccountCode'] = account_code if account_code
71
+ creds['req:Password'] = password
72
+ creds['req:UserName'] = username
73
+
74
+ # Loop to obtain Ticket
75
+ c = nil
76
+ ticket = nil
77
+ until ticket
78
+
79
+ # Authenticate
80
+ begin
81
+ c = open next_url
82
+ r = c.call(:pws_authenticate, message: { 'pws:serviceRequest' => creds }).body[:pws_authenticate_response][:pws_authenticate_result]
83
+ last_url = next_url
84
+ next_url = r[:redirect_url]
85
+ rescue Savon::SOAPFault => e
86
+ raise "Authentication failed - #{e.to_hash[:fault][:detail][:pws_fault][:messages][:pws_message][:error_text]}"
87
+ end
88
+
89
+ raise 'API Error (redirect loop)' if next_url == last_url
90
+ ticket = r[:session_ticket]
91
+ end
92
+
93
+ # Yield if block given
94
+ if block_given?
95
+ r = yield c, ticket
96
+ unauthenticate c, ticket
97
+ return r
98
+ end
99
+
100
+ [c, ticket]
101
+ end
102
+
103
+ # Unauthenticate
104
+ def self.unauthenticate c, ticket
105
+
106
+ # Unauthenticate
107
+ c.call(:pws_unauthenticate, message: { 'pws:serviceRequest' => { 'req:SessionTicket' => ticket } }).body
108
+ end
109
+
110
+ # Get Resources
111
+ def self.get_resources c, ticket
112
+
113
+ # Fetch Resources
114
+ c.call(:pws_get_resource_list, message: { 'pws:serviceRequest' => { 'req:SessionTicket' => ticket } }).body[:pws_get_resource_list_response][:pws_get_resource_list_result][:resources][:pws_resource_summary]
115
+ end
116
+
117
+ # Get Resource Schedule
118
+ def self.get_resource_schedule c, ticket, resource_uid, start_date = current_week_start, end_date = current_week_end
119
+
120
+ # Prepare Params
121
+ params = { 'req:SessionTicket' => ticket }
122
+ params['tim:EndDate'] = end_date.strftime '%Y-%m-%dz'
123
+ params['tim:IncludeScheduledTimeFlag'] = :true
124
+ params['tim:IncludeTimeOffFlag'] = :true
125
+ params['tim:ResourceIdentity'] = { 'com:ResourceUid' => resource_uid }
126
+ params['tim:StartDate'] = start_date.strftime '%Y-%m-%dz'
127
+
128
+ # Fetch Resource Schedule
129
+ c.call(:pws_get_resource_schedule, message: { 'pws:serviceRequest' => params }).body[:pws_get_resource_schedule_response][:pws_get_resource_schedule_result][:resource_schedule]
130
+ end
131
+
132
+ # Get Resource Working Schedule
133
+ def self.get_resource_working_schedule c, ticket, resource_uid, start_date = current_week_start, end_date = current_week_end
134
+
135
+ # Prepare Params
136
+ params = { 'req:SessionTicket' => ticket }
137
+ params['tim:EndDate'] = end_date.strftime '%Y-%m-%dz'
138
+ params['tim:ResourceIdentity'] = { 'com:ResourceUid' => resource_uid }
139
+ params['tim:StartDate'] = start_date.strftime '%Y-%m-%dz'
140
+
141
+ # Fetch Resource Working Schedule
142
+ c.call(:pws_get_resource_working_schedule, message: { 'pws:serviceRequest' => params }).body[:pws_get_resource_working_schedule_response][:pws_get_resource_working_schedule_result][:working_schedule]
143
+ end
144
+
145
+ # Get Free Resources (non-busy) with associated minutes
146
+ def self.get_free_resources c, ticket, start_date = current_week_start, end_date = current_week_end
147
+
148
+ # Get all resources
149
+ res = ProjectorPWS.get_resources c, ticket
150
+
151
+ # Collect free time
152
+ res.collect { |r| {
153
+ resource: r,
154
+ free_hours: get_resource_free_hours(c, ticket, r, start_date, end_date).to_f
155
+ } }.select { |x| x[:free_hours] > 0 }
156
+ end
157
+
158
+ # Get Resource Free Hours
159
+ def self.get_resource_free_hours c, ticket, resource, start_date = current_week_start, end_date = current_week_end
160
+
161
+ # Get scheduled hours
162
+ scheduled_hours = get_resource_scheduled_hours c, ticket, resource, start_date, end_date
163
+
164
+ # Get active hours
165
+ active_hours = get_resource_active_hours c, ticket, resource, start_date, end_date
166
+
167
+ # Compute time off into active hours
168
+ active_hours = active_hours - scheduled_hours[:toff]
169
+
170
+ # Compute free time (active unscheduled time)
171
+ active_hours - scheduled_hours[:work]
172
+ end
173
+
174
+ # Get Resource Active Hours
175
+ def self.get_resource_active_hours c, ticket, resource, start_date = current_week_start, end_date = current_week_end
176
+
177
+ # Acquire working schedule for resource
178
+ wsched = ProjectorPWS.get_resource_working_schedule(c, ticket, resource[:resource_uid], start_date, end_date)[:pws_working_schedule_day] rescue(return(0))
179
+ wsched = [wsched] unless wsched.is_a? Array
180
+ wsched.compact!
181
+
182
+ # Extract Working Minutes
183
+ work = wsched.inject(0) { |a, e| a + e[:working_minutes].to_i }
184
+
185
+ # Determine Active Hours
186
+ work.to_f / MINUTES_PER_HOUR.to_f
187
+ end
188
+
189
+ # Get Resource Scheduled Hours
190
+ def self.get_resource_scheduled_hours c, ticket, resource, start_date = current_week_start, end_date = current_week_end
191
+
192
+ # Get schedule
193
+ sched = get_resource_schedule(c, ticket, resource[:resource_uid], start_date, end_date) rescue(return({ work: 0, toff: 0 }))
194
+
195
+ # Extract scheduled work
196
+ sched_work = sched[:roles][:pws_schedule_role] rescue []
197
+ sched_work = [sched_work] unless sched_work.is_a? Array
198
+ sched_work.compact!
199
+
200
+ # Extract scheduled time off
201
+ time_off = sched[:time_off][:pws_schedule_time_off] rescue []
202
+ time_off = [time_off] unless time_off.is_a? Array
203
+ time_off.compact!
204
+
205
+ # Run through time off { collect total minutes }
206
+ time_off_minutes = time_off.inject(0) do |a, e|
207
+
208
+ # Extract Dates
209
+ dates = e[:time_off_dates][:pws_schedule_time_off_date] rescue []
210
+ dates = [dates] unless dates.is_a? Array
211
+ dates.compact!
212
+
213
+ # Collect time off dates
214
+ a + dates.inject(0) { |da, de| da + time_off_minutes(de[:time_off_minutes].to_i) }
215
+ end
216
+
217
+ # Run through schedule { collect total minutes }
218
+ scheduled_minutes = sched_work.inject(0) do |a, e|
219
+
220
+ # Extract bookings
221
+ bookings = e[:bookings][:pws_schedule_booking] rescue []
222
+ bookings = [bookings] unless bookings.is_a? Array
223
+ bookings.compact!
224
+
225
+ # Collect 'busy' bookings
226
+ e[:project_descriptor][:engagement_descriptor][:engagement_type_descriptor][:busy_flag] ? a + (bookings.inject(0) { |ba, be| ba + be[:scheduled_minutes].to_i }) : a
227
+ end
228
+
229
+ {
230
+ work: scheduled_minutes.to_f / MINUTES_PER_HOUR.to_f,
231
+ toff: time_off_minutes.to_f / MINUTES_PER_HOUR.to_f
232
+ }
233
+ end
234
+
235
+ # Generate Service URL
236
+ def self.service_url base_url
237
+ "#{base_url}/#{URL_PATH}"
238
+ end
239
+
240
+ # Current Week Start
241
+ def self.current_week_start
242
+ is_weekend? ? Date.today.wnext(WEEK_START) : Date.today.wlast(WEEK_START)
243
+ end
244
+
245
+ # Current Week End
246
+ def self.current_week_end
247
+ current_week_start.wnext(WEEK_END)
248
+ end
249
+
250
+ # Is Weekend
251
+ def self.is_weekend?
252
+ Date.today.friday? || Date.today.saturday? || Date.today.sunday?
253
+ end
254
+
255
+ # Time Off Minutes (adjust for full-day holidays)
256
+ def self.time_off_minutes x
257
+ (x == HOURS_PER_DAY_REAL * MINUTES_PER_HOUR) ? (HOURS_PER_DAY * MINUTES_PER_HOUR) : x
258
+ end
259
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'projector_pws/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'projector_pws'
8
+ spec.version = ProjectorPWS::VERSION
9
+ spec.authors = ['Eresse']
10
+ spec.email = ['eresse@eresse.net']
11
+
12
+ spec.summary = 'Projector PWS Client Library'
13
+ spec.description = 'Provides access to Projector PSA\'s Web Services (PWS)'
14
+ spec.homepage = 'http://redmine.eresse.net/projects/projector_pws'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_development_dependency 'bundler'
21
+ spec.add_development_dependency 'rake'
22
+ spec.add_runtime_dependency 'minitest'
23
+ spec.add_runtime_dependency 'aromat'
24
+ spec.add_runtime_dependency 'savon'
25
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: projector_pws
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Eresse
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-16 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: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
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: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: aromat
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: savon
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Provides access to Projector PSA's Web Services (PWS)
84
+ email:
85
+ - eresse@eresse.net
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - Gemfile
92
+ - LICENSE.txt
93
+ - README.md
94
+ - Rakefile
95
+ - lib/projector_pws.rb
96
+ - lib/projector_pws/version.rb
97
+ - projector_pws.gemspec
98
+ homepage: http://redmine.eresse.net/projects/projector_pws
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.5.1
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Projector PWS Client Library
122
+ test_files: []