springcm-sdk 0.3.2 → 0.3.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08e2b1331f3dcb52b9ae6046ba374275586f58f287e7b47ab21d5d3e2b8733d5'
4
- data.tar.gz: 7a5c41aed3ca626531c71527c1a30cbd2bd445b2f7eb001dadae940df843e1c3
3
+ metadata.gz: 4ad5c7b8f5ee94f60381f7a7c1584dade0d0e3a060f7a2914063e0d5c044db61
4
+ data.tar.gz: b314ab30a1191edf5df3ff00d629cb45184d01e10e12819b425c8a65c87b78a4
5
5
  SHA512:
6
- metadata.gz: 8057fdf959e404fa084073027b9efed06b1ae04c6cb02ce6db7b15b225c961cd0e426a84ddc894fe946fcba4e58ea77781ce24ea25c2b08cb801a284bc32369b
7
- data.tar.gz: c5781be7af9eee9a5493e75af6ecf5d0e1b7edc3df7efddd6379c9b3c1f2e576c2c62662486abe21cdd72e3ed5fc689456610f1a8ecac4cd66a74500f5cd2f21
6
+ metadata.gz: 05db834bd55f338e04f3d8b6275d87aa41727823300f339771934fe190eda689ff1b6e4fc120f9d9b7e00d6a7b4b8cc2961189af1ebde8bf1675d51d91658fde
7
+ data.tar.gz: 2d35b5c934bb4fe530e1f7e7d0ffd5f0424e1f1b8f63da0ae17c757d7d57003acc6c2e69398b42f00606b06489aa8425d8fd07501727381dc7ad346879c3f155
data/CHANGELOG.md CHANGED
@@ -4,6 +4,27 @@ All notable changes to springcm-sdk will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.3.4] - 2019-12-11
8
+ ### Added
9
+ * Folder#delete
10
+ * Document#delete
11
+ * Client#document (by path or UID)
12
+ * Folder#move (by destination folder path or UID)
13
+ * Document#move (by destination folder path or UID)
14
+ * Account#attribute_groups
15
+ * Mixins::Attributes#get_attribute
16
+
17
+ ### Changed
18
+ * Tweaked PageBuilder to support items that don't have a parent folder.
19
+ Instead uses a base HREF to build next/prev/first/last HREFs. Similarly
20
+ modified ResourceBuilder to reference a parent object instead of a parent
21
+ folder. Outside of folders/documents, this parent object will simply be
22
+ the Account.
23
+
24
+ ## [0.3.3] - 2019-11-12
25
+ ### Changed
26
+ * Fix issue with getting root folder by path
27
+
7
28
  ## [0.3.2]
8
29
  ### Changed
9
30
  * Fix issue with JSON library not being required
@@ -48,7 +69,7 @@ All notable changes to springcm-sdk will be documented in this file.
48
69
  ### Added
49
70
  * Initial release to reserve gem name
50
71
 
51
- [Unreleased]: https://github.com/paulholden2/springcm-sdk/compare/0.3.2...HEAD
72
+ [Unreleased]: https://github.com/paulholden2/springcm-sdk/compare/0.3.4...HEAD
52
73
  [0.1.0]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.1.0
53
74
  [0.1.1]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.1.1
54
75
  [0.1.2]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.1.2
@@ -56,3 +77,5 @@ All notable changes to springcm-sdk will be documented in this file.
56
77
  [0.3.0]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.3.0
57
78
  [0.3.1]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.3.1
58
79
  [0.3.2]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.3.2
80
+ [0.3.3]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.3.3
81
+ [0.3.4]: https://github.com/paulholden2/springcm-sdk/releases/tag/0.3.4
@@ -1,6 +1,50 @@
1
1
  require "springcm-sdk/object"
2
+ require "springcm-sdk/attribute_group"
2
3
 
3
4
  module Springcm
4
5
  class Account < Object
6
+ def initialize(data, client)
7
+ super(data, client)
8
+ @all_attribute_groups = nil
9
+ end
10
+
11
+ # Retrieve all attribute groups for this account. Calls #attribute_groups
12
+ # and concatenates results to a cache that is returned from future calls
13
+ # to #all_attribute_groups.
14
+ def all_attribute_groups
15
+ if @all_attribute_groups.nil?
16
+ load_all_attribute_groups
17
+ end
18
+ @all_attribute_groups
19
+ end
20
+
21
+ # Retrieve a page of attribute groups in this account. In most cases,
22
+ # you can call #all_attribute_groups instead, as attribute group
23
+ # configurations do not frequently change.
24
+ def attribute_groups(offset: 0, limit: 20)
25
+ conn = @client.authorized_connection(url: @client.object_api_url)
26
+ res = conn.get do |req|
27
+ req.url "accounts/current/attributegroups"
28
+ req.params["offset"] = offset
29
+ req.params["limit"] = limit
30
+ end
31
+ if res.success?
32
+ data = JSON.parse(res.body)
33
+ ResourceList.new(data, self, AttributeGroup, @client)
34
+ else
35
+ nil
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def load_all_attribute_groups
42
+ @all_attribute_groups = []
43
+ list = attribute_groups(offset: 0, limit: 20)
44
+ while !list.nil?
45
+ @all_attribute_groups.concat(list.items)
46
+ list = list.next
47
+ end
48
+ end
5
49
  end
6
50
  end
@@ -0,0 +1,17 @@
1
+ require "springcm-sdk/resource"
2
+
3
+ module Springcm
4
+ class Attribute < Resource
5
+ def required?
6
+ required
7
+ end
8
+
9
+ def read_only?
10
+ read_only
11
+ end
12
+
13
+ def repeating_attribute?
14
+ repeating_attribute
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,56 @@
1
+ require "springcm-sdk/resource"
2
+ require "springcm-sdk/attribute"
3
+
4
+ module Springcm
5
+ # A configured attribute group in SpringCM.
6
+ class AttributeGroup < Resource
7
+ # Retrieve an attribute set by name.
8
+ def set(name)
9
+ res = @data["Attributes"].select { |attr|
10
+ attr["Attributes"].is_a?(Array) && attr["Name"] == name
11
+ }
12
+ return nil if !res.any?
13
+ res.first["Attributes"].map { |attr|
14
+ Attribute.new(attr, @client)
15
+ }
16
+ end
17
+
18
+ # Retrieve an attribute field by name.
19
+ def field(name)
20
+ res = attributes.select { |attr|
21
+ attr["Name"] == name
22
+ }
23
+ return nil if !res.any?
24
+ # TODO: Assert only one result
25
+ Attribute.new(res.first, @client)
26
+ end
27
+
28
+ def set_for_field(name)
29
+ if sets.map { |set| set["Name"] }.include?(name)
30
+ return nil
31
+ end
32
+ sets.each { |set|
33
+ if set["Attributes"].map { |attr| attr["Name"] }.include?(name)
34
+ return set
35
+ end
36
+ }
37
+ nil
38
+ end
39
+
40
+ def attributes
41
+ @data["Attributes"].map { |attr|
42
+ if attr["Attributes"].is_a?(Array)
43
+ attr["Attributes"]
44
+ else
45
+ [attr]
46
+ end
47
+ }.flatten
48
+ end
49
+
50
+ def sets
51
+ @data["Attributes"].select { |attr|
52
+ attr["Attributes"].is_a?(Array)
53
+ }
54
+ end
55
+ end
56
+ end
@@ -95,6 +95,9 @@ module Springcm
95
95
  if (path.nil? && uid.nil?) || (!path.nil? && !uid.nil?)
96
96
  raise ArgumentError.new("Specify exactly one of: path, uid")
97
97
  end
98
+ if path == "/"
99
+ return root_folder
100
+ end
98
101
  conn = authorized_connection(url: object_api_url)
99
102
  res = conn.get do |req|
100
103
  if !path.nil?
@@ -103,6 +106,9 @@ module Springcm
103
106
  elsif !uid.nil?
104
107
  req.url "folders/#{uid}"
105
108
  end
109
+ Folder.resource_params.each { |key, value|
110
+ req.params[key] = value
111
+ }
106
112
  end
107
113
  if res.success?
108
114
  data = JSON.parse(res.body)
@@ -112,6 +118,30 @@ module Springcm
112
118
  end
113
119
  end
114
120
 
121
+ def document(path: nil, uid: nil)
122
+ if (path.nil? && uid.nil?) || (!path.nil? && !uid.nil?)
123
+ raise ArgumentError.new("Specify exactly one of: path, uid")
124
+ end
125
+ conn = authorized_connection(url: object_api_url)
126
+ res = conn.get do |req|
127
+ if !path.nil?
128
+ req.url "documents"
129
+ req.params["path"] = path
130
+ elsif !uid.nil?
131
+ req.url "documents/#{uid}"
132
+ end
133
+ Document.resource_params.each { |key, value|
134
+ req.params[key] = value
135
+ }
136
+ end
137
+ if res.success?
138
+ data = JSON.parse(res.body)
139
+ return Document.new(data, self)
140
+ else
141
+ nil
142
+ end
143
+ end
144
+
115
145
  # Check if client is successfully authenticated
116
146
  # @return [Boolean] Whether a valid, unexpired access token is held.
117
147
  def authenticated?
@@ -1,8 +1,17 @@
1
1
  require "springcm-sdk/resource"
2
2
  require "springcm-sdk/mixins/access_level"
3
+ require "springcm-sdk/mixins/attributes"
3
4
 
4
5
  module Springcm
5
6
  class Document < Resource
6
- include Springcm::AccessLevel
7
+ include Springcm::Mixins::AccessLevel
8
+ include Springcm::Mixins::ParentFolder
9
+ include Springcm::Mixins::Attributes
10
+
11
+ def self.resource_params
12
+ {
13
+ "expand" => "attributegroups"
14
+ }
15
+ end
7
16
  end
8
17
  end
@@ -7,15 +7,22 @@ require "springcm-sdk/helpers"
7
7
 
8
8
  module Springcm
9
9
  class Folder < Resource
10
- include Springcm::AccessLevel
11
- include Springcm::ParentFolder
12
- include Springcm::Documents
10
+ include Springcm::Mixins::AccessLevel
11
+ include Springcm::Mixins::ParentFolder
12
+ include Springcm::Mixins::Documents
13
13
 
14
+ def self.resource_params
15
+ {
16
+ "expand" => "attributegroups"
17
+ }
18
+ end
19
+
20
+ # Retrieve a page of folders contained in this folder.
14
21
  def folders(offset: 0, limit: 20)
15
22
  Helpers.validate_offset_limit!(offset, limit)
16
23
  conn = @client.authorized_connection(url: @client.object_api_url)
17
24
  res = conn.get do |req|
18
- req.url "folders/#{uid}/folders"
25
+ req.url "#{resource_uri}/folders"
19
26
  req.params["offset"] = offset
20
27
  req.params["limit"] = limit
21
28
  end
@@ -27,12 +34,16 @@ module Springcm
27
34
  end
28
35
  end
29
36
 
37
+ # Retrieve the containing folder.
30
38
  def parent_folder
31
39
  uri = URI(parent_folder_href)
32
40
  url = "#{uri.scheme}://#{uri.host}"
33
41
  conn = @client.authorized_connection(url: url)
34
42
  res = conn.get do |req|
35
43
  req.url uri.path
44
+ resource_params.each { |key, value|
45
+ req.params[key] = value
46
+ }
36
47
  end
37
48
  if res.success?
38
49
  data = JSON.parse(res.body)
@@ -42,6 +53,7 @@ module Springcm
42
53
  end
43
54
  end
44
55
 
56
+ # Retrieve a page of documents in this folder.
45
57
  def documents(offset: 0, limit: 20)
46
58
  Helpers.validate_offset_limit!(offset, limit)
47
59
  uri = URI(documents_href)
@@ -1,5 +1,6 @@
1
1
  module Springcm
2
2
  module Helpers
3
+ # Validate an offset and limit pair.
3
4
  def self.validate_offset_limit!(offset, limit)
4
5
  if !limit.is_a?(Integer) || limit < 1 || limit > 1000
5
6
  raise ArgumentError.new("Limit must be an integer between 1 and 1000 (inclusive).")
@@ -1,37 +1,40 @@
1
1
  module Springcm
2
- module AccessLevel
3
- # @return [Boolean] Does the API user have see permission
4
- def see?
5
- !!access_level.dig("See")
6
- end
2
+ module Mixins
3
+ # Mixin for objects that have security attached, e.g. folders.
4
+ module AccessLevel
5
+ # @return [Boolean] Does the API user have see permission
6
+ def see?
7
+ !!access_level.dig("See")
8
+ end
7
9
 
8
- # @return [Boolean] Does the API user have read permission
9
- def read?
10
- !!access_level.dig("Read")
11
- end
10
+ # @return [Boolean] Does the API user have read permission
11
+ def read?
12
+ !!access_level.dig("Read")
13
+ end
12
14
 
13
- # @return [Boolean] Does the API user have write permission
14
- def write?
15
- !!access_level.dig("Write")
16
- end
15
+ # @return [Boolean] Does the API user have write permission
16
+ def write?
17
+ !!access_level.dig("Write")
18
+ end
17
19
 
18
- # @return [Boolean] Does the API user have move permission
19
- def move?
20
- !!access_level.dig("Move")
21
- end
20
+ # @return [Boolean] Does the API user have move permission
21
+ def move?
22
+ !!access_level.dig("Move")
23
+ end
22
24
 
23
- # @return [Boolean] Does the API user have create permission
24
- def create?
25
- !!access_level.dig("Create")
26
- end
25
+ # @return [Boolean] Does the API user have create permission
26
+ def create?
27
+ !!access_level.dig("Create")
28
+ end
27
29
 
28
- # @return [Boolean] Does the API user have set access permission
29
- def set_access?
30
- !!access_level.dig("SetAccess")
31
- end
30
+ # @return [Boolean] Does the API user have set access permission
31
+ def set_access?
32
+ !!access_level.dig("SetAccess")
33
+ end
32
34
 
33
- def access_level
34
- @data.fetch("AccessLevel")
35
+ def access_level
36
+ @data.fetch("AccessLevel")
37
+ end
35
38
  end
36
39
  end
37
40
  end
@@ -0,0 +1,52 @@
1
+ module Springcm
2
+ module Mixins
3
+ # Mixin for objects that have attributes.
4
+ module Attributes
5
+ def deserialize_field(field)
6
+ type = field["AttributeType"]
7
+ value = field["Value"]
8
+ if type == "String"
9
+ value
10
+ elsif type == "Number"
11
+ value.to_i
12
+ elsif type == "Decimal"
13
+ value.to_f
14
+ elsif type == "Date"
15
+ Date.strptime(value[0..8], "%Y%m%d")
16
+ else
17
+ value
18
+ end
19
+ end
20
+
21
+ def get_attribute(group:, field:)
22
+ group_config = @client.account.all_attribute_groups.select { |g|
23
+ g.name == group
24
+ }.first
25
+ # Non-existent group
26
+ return nil if group_config.nil?
27
+ field_config = group_config.field(field)
28
+ field_set_config = group_config.set_for_field(field)
29
+ # Non-existent field
30
+ return nil if field_config.nil?
31
+ groups = attribute_groups
32
+ # No attribute groups applied
33
+ return nil if groups.nil?
34
+ group_data = groups.fetch(group, nil)
35
+ # Group is not applied
36
+ return nil if group_data.nil?
37
+ # Repeating set
38
+ if !field_set_config.nil? && field_set_config["RepeatingAttribute"]
39
+ set_data = group_data.fetch(field_set_config["Name"], nil)
40
+ return nil if set_data.nil?
41
+ set_data["Items"].map { |item|
42
+ deserialize_field(item[field])
43
+ }
44
+ else
45
+ field_data = group_data.fetch(field, nil)
46
+ return nil if field_data.nil?
47
+ deserialize_field(field_data)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,7 +1,9 @@
1
1
  module Springcm
2
- module Documents
3
- def documents_href
4
- @data.dig("Documents", "Href")
2
+ module Mixins
3
+ module Documents
4
+ def documents_href
5
+ @data.dig("Documents", "Href")
6
+ end
5
7
  end
6
8
  end
7
9
  end
@@ -1,8 +1,30 @@
1
1
  module Springcm
2
- module ParentFolder
3
- def parent_folder_href
4
- # Root folders won't have ParentFolder key
5
- @data.dig("ParentFolder", "Href")
2
+ module Mixins
3
+ # Mixin for objects that have a parent folder.
4
+ module ParentFolder
5
+ def parent_folder_href
6
+ # Root folders won't have ParentFolder key
7
+ @data.dig("ParentFolder", "Href")
8
+ end
9
+
10
+ def move(path: nil, uid: nil)
11
+ parent = @client.folder(path: path, uid: uid)
12
+ body = {
13
+ "ParentFolder" => parent.raw
14
+ }
15
+ conn = @client.authorized_connection(url: @client.object_api_url)
16
+ res = conn.patch do |req|
17
+ req.headers["Content-Type"] = "application/json"
18
+ req.url resource_uri
19
+ req.body = body.to_json
20
+ end
21
+ if res.success?
22
+ data = JSON.parse(res.body)
23
+ self.class.new(data, @client)
24
+ else
25
+ nil
26
+ end
27
+ end
6
28
  end
7
29
  end
8
30
  end
@@ -5,6 +5,15 @@ module Springcm
5
5
  @data = data
6
6
  end
7
7
 
8
+ # Retrieve a top-level property of the object's JSON data.
9
+ #
10
+ # For convenience, top-level properties of a SpringCM object's JSON data
11
+ # are accessible via instance methods (underscore format), e.g.
12
+ # attribute_groups to retrieve JSON for $.AttributeGroups. This can be and
13
+ # is often overridden by inheriting classes by defining a method and
14
+ # extending what it does. Some mixins also provide convenience methods
15
+ # for retrieving data deeper in the JSON document, e.g. documents_href
16
+ # via Springcm::Mixins::Documents.
8
17
  def method_missing(m, *args, &block)
9
18
  key = m.to_s.split("_").map(&:capitalize).join
10
19
  if @data.key?(key)
@@ -13,5 +22,10 @@ module Springcm
13
22
  super
14
23
  end
15
24
  end
25
+
26
+ # Retrieve the raw JSON document for this object.
27
+ def raw
28
+ @data
29
+ end
16
30
  end
17
31
  end
@@ -1,10 +1,65 @@
1
1
  require "springcm-sdk/object"
2
2
 
3
3
  module Springcm
4
+ # A Resource is a SpringCM object that has an auto-assigned GUID.
4
5
  class Resource < Object
5
- # @return [String] The folder unique identifier (UID)
6
+ # @return [String] The object's unique identifier (UID)
6
7
  def uid
7
8
  href[-36..-1]
8
9
  end
10
+
11
+ # Resend a request to the API for this resource and return a new instance.
12
+ def reload
13
+ get
14
+ end
15
+
16
+ # Send a GET request for this resource.
17
+ def get
18
+ conn = @client.authorized_connection(url: @client.object_api_url)
19
+ res = conn.get do |req|
20
+ req.url resource_uri
21
+ resource_params.each { |key, value|
22
+ req.params[key] = value
23
+ }
24
+ end
25
+ if res.success?
26
+ data = JSON.parse(res.body)
27
+ self.class.new(data, @client)
28
+ else
29
+ nil
30
+ end
31
+ end
32
+
33
+ # Send a DELETE request for this resource.
34
+ def delete
35
+ conn = @client.authorized_connection(url: @client.object_api_url)
36
+ res = conn.delete do |req|
37
+ req.url resource_uri
38
+ end
39
+ if res.success?
40
+ data = JSON.parse(res.body)
41
+ reload
42
+ else
43
+ nil
44
+ end
45
+ end
46
+
47
+ # Retrieve the URI for this resource (relative to the base object API
48
+ # URL).
49
+ def resource_uri
50
+ "#{resource_name}/#{uid}"
51
+ end
52
+
53
+ # Some resources have query parameters that must be passed when
54
+ # retrieving it, e.g. expand=attributegroups when retrieving a document.
55
+ def resource_params
56
+ {}
57
+ end
58
+
59
+ # Pluralized resource name, e.g. documents or folders. Used to construct
60
+ # request URLs.
61
+ def resource_name
62
+ "#{self.class.to_s.split("::").last.downcase}s"
63
+ end
9
64
  end
10
65
  end
@@ -1,7 +1,11 @@
1
1
  module Springcm
2
+ # A list object of arbitrary SpringCM resources. Allows for easy navigation
3
+ # of paged resources like documents and attribute groups. All resources
4
+ # that are retrieved in this manner are attached to a parent object, e.g.
5
+ # the account for attribute groups, or a folder for documents.
2
6
  class ResourceList < Object
3
- def initialize(data, parent_folder, kind, client)
4
- @parent_folder = parent_folder
7
+ def initialize(data, parent_object, kind, client)
8
+ @parent_object = parent_object
5
9
  @kind = kind
6
10
  super(data, client)
7
11
  end
@@ -38,7 +42,7 @@ module Springcm
38
42
  query = CGI.parse(uri.query || "")
39
43
  offset = query.fetch("offset", ["0"]).first.to_i
40
44
  limit = query.fetch("limit", ["20"]).first.to_i
41
- @parent_folder.send(method, offset: offset, limit: limit)
45
+ @parent_object.send(method, offset: offset, limit: limit)
42
46
  end
43
47
 
44
48
  def method_for_kind!(kind)
@@ -47,8 +51,10 @@ module Springcm
47
51
  method = :folders
48
52
  elsif kind == Springcm::Document
49
53
  method = :documents
54
+ elsif kind == Springcm::AttributeGroup
55
+ method = :attribute_groups
50
56
  else
51
- raise ArgumentError.new("Resource kind must be one of: Springcm::Document, Springcm::Folder.")
57
+ raise ArgumentError.new("Resource kind must be one of: Springcm::Document, Springcm::Folder, Springcm::AttributeGroup.")
52
58
  end
53
59
  return method
54
60
  end
@@ -1,3 +1,3 @@
1
1
  module Springcm
2
- VERSION = "0.3.2"
2
+ VERSION = "0.3.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: springcm-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Holden
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-08 00:00:00.000000000 Z
11
+ date: 2019-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -160,11 +160,14 @@ files:
160
160
  - exe/springcm
161
161
  - lib/springcm-sdk.rb
162
162
  - lib/springcm-sdk/account.rb
163
+ - lib/springcm-sdk/attribute.rb
164
+ - lib/springcm-sdk/attribute_group.rb
163
165
  - lib/springcm-sdk/client.rb
164
166
  - lib/springcm-sdk/document.rb
165
167
  - lib/springcm-sdk/folder.rb
166
168
  - lib/springcm-sdk/helpers.rb
167
169
  - lib/springcm-sdk/mixins/access_level.rb
170
+ - lib/springcm-sdk/mixins/attributes.rb
168
171
  - lib/springcm-sdk/mixins/documents.rb
169
172
  - lib/springcm-sdk/mixins/parent_folder.rb
170
173
  - lib/springcm-sdk/object.rb
@@ -179,7 +182,7 @@ metadata:
179
182
  allowed_push_host: https://rubygems.org
180
183
  homepage_uri: https://github.com/paulholden2/springcm-sdk
181
184
  source_code_uri: https://github.com/paulholden2/springcm-sdk
182
- documentation_uri: https://rubydoc.info/github/paulholden2/springcm-sdk/0.3.2
185
+ documentation_uri: https://rubydoc.info/github/paulholden2/springcm-sdk/0.3.4
183
186
  changelog_uri: https://github.com/paulholden2/springcm-sdk/blob/master/CHANGELOG.md
184
187
  post_install_message:
185
188
  rdoc_options: []