chameleon-ruby 0.1.6

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 063b39158b4215a5571222f799ac1780895db5710d667507041eb984985ab62f
4
+ data.tar.gz: 65939c62ec99e9e0bcd177515aa6faf54d291264c5e2273c8f203f0e259b1e31
5
+ SHA512:
6
+ metadata.gz: 35920fd3e874f5a10aeaa6a1b2b9ac66186fa52f4a021cd9b8cdbe819c70ef6ee92b0c0e14c06e1356bb824891ee0717014a98c0f8e83b9bed7cf27117fbedd8
7
+ data.tar.gz: e13d11ac0ca4c0f8e0dbcf0031e44577253c610c6ab638153f6cf096ba8740bb9f3f3441674fb0127b564b08205060b831881dd29fdd9ffa31047e6969ce93cb
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Brian Norton
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,139 @@
1
+ # chameleon-ruby
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/chameleon-ruby.svg)](https://rubygems.org/gems/chameleon-ruby)
4
+ [![CI](https://github.com/chamaeleonidae/chameleon-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/chamaeleonidae/chameleon-ruby/actions/workflows/ci.yml)
5
+
6
+ A Ruby gem for simple interactions with the Chameleon APIs
7
+
8
+ > Your API Secret is generated on the [Integrations page](https://app.chameleon.io/integrations/tokens). The Full API documentation can be found on our [Developer hub](https://developers.chameleon.io)!
9
+
10
+ ---
11
+
12
+ - [Quick start](#quick-start)
13
+ - [Usage and Examples](#usage-and-examples)
14
+ - [Support](#support)
15
+ - [License](#license)
16
+ - [Code of conduct](#code-of-conduct)
17
+ - [Contribution guide](#contribution-guide)
18
+
19
+ ## Quick start
20
+
21
+ ```ruby
22
+ gem 'chameleon-ruby' # in your Gemfile
23
+ ```
24
+
25
+ ```ruby
26
+ require 'chameleon' # if needed
27
+ ```
28
+
29
+ ## Usage and Examples
30
+
31
+ ```ruby
32
+ # configs/initializers/chameleon/rb
33
+ Chameleon.configure do |config|
34
+ config.secret = ENV['CHAMELEON_SECRET']
35
+ end
36
+ ```
37
+
38
+ ```ruby
39
+ ##
40
+ # In a Background job when content is created / updated
41
+ #
42
+ Chameleon::SearchItem.index(uid, title: title, actions: actions)
43
+
44
+ ##
45
+ # More options and inspiration for what you can do
46
+ #
47
+ # This example assumes you have a model in your database called `Document` but
48
+ # this can be anything users can create in your system
49
+ #
50
+
51
+ uid = "documents:#{model.id}" # or "#{model.class.name.underscore}:#{model.id}"
52
+
53
+ title = model.name # the main unit of searchability; for a document this is the user generated title; for a
54
+ description = model.description # user generated description; may include tags or other identifying info about this content
55
+
56
+ actions = [{ kind: 'navigate', url: "/documents/#{model.id}/edit" }] # navigate to /documents/3327/edit when clicked
57
+ # or
58
+ actions = [{ kind: 'navigate', url: "/#{model.class.name.underscore}/#{model.id}/edit" }] # navigate to /documents/3327/edit when clicked
59
+
60
+ icon = { kind: 'uid', uid: 'cog' } # the icon displayed for this item from the Chameleon icon library
61
+ # or
62
+ icon = { kind: 'image', image_url: 'https://cdn-icons-png.flaticon.com/512/9908/9908192.png' } # the icon displayed for this item from a public url
63
+
64
+ ##
65
+ # Index the content by uid
66
+ #
67
+ Chameleon::SearchItem.index(uid, title: title, actions: actions)
68
+
69
+ # Remove when deleted/archived in your system or no longer searchable
70
+ #
71
+ Chameleon::SearchItem.remove(uid)
72
+
73
+ ##
74
+ # Add a user-generated description, if you have it
75
+ #
76
+ Chameleon::SearchItem.index(uid, title: title, description: description, actions: actions)
77
+
78
+ ##
79
+ # Customize the icon from the Chameleon icon library
80
+ #
81
+ icon = { kind: 'uid', uid: 'cog' } # the icon displayed for this item from the Chameleon icon library
82
+ Chameleon::SearchItem.index(uid, title: title, actions: actions, icon: icon)
83
+
84
+ ##
85
+ # To restrict content to a specific Chameleon user, set the profile_uids to just that single user
86
+ # This is the only user that will be able to find this content
87
+ #
88
+ # Use cases:
89
+ # - This document is only visible to the creator
90
+ # - This design or prototype has not been shared yet
91
+ # - A part of the users' onboarding that is not yet complete
92
+ #
93
+ Chameleon::SearchItem.index(uid, title: title, description: description, actions: actions, profile_uids: [user.id])
94
+
95
+ ##
96
+ # Now to extend the Use case to a Document that the creator shares with their co-workers
97
+ # This example assumes that Document has an array of User IDs (an ACL) to share with
98
+ #
99
+ Chameleon::SearchItem.index(uid, title: title, actions: actions, profile_uids: [user.id, *document.shared_to_user_ids])
100
+
101
+ ##
102
+ # To restrict content to a specific Chameleon company, set the company_uids to just that single company
103
+ # This is the only company that will be able to find this content -- all users in this company are able to search for it
104
+ #
105
+ # Use cases:
106
+ # - This document is only visible to the Company/Account/Tenant of the creator
107
+ # - This design or prototype has been published/shared to your Company
108
+ # - A part of the company's onboarding that is not yet complete
109
+ #
110
+ Chameleon::SearchItem.index(uid, title: title, actions: actions, company_uids: [company.id])
111
+
112
+ ##
113
+ # To restrict content to a specific Chameleon Segment, set the segment_ids to one or many Segments
114
+ # Only current members of these Segments will be able to search for this content
115
+ #
116
+ # Use cases:
117
+ # - This document is only visible to Company/Account/Tenant administrators (Segment is set to "roles contains admin")
118
+ # - This page is only available to the Enterprise plan (Segment is set to is "plan is enterprise")
119
+ # - An upsell prompt is only relevant for trialing users (Segment is set to "plan_status is trialing")
120
+ #
121
+ Chameleon::SearchItem.index(uid, title: title, actions: actions, segment_ids: [segment1_id, segment2_id])
122
+ ```
123
+
124
+ #### Support
125
+
126
+ If you want to report a bug, or have ideas, feedback or questions about the gem itself, [let us know via GitHub issues](https://github.com/chamaeleonidae/chameleon-ruby/issues/new) and the Chameleon team will do their best to provide a helpful answer.
127
+ Or another to reach us is to [Contact us](https://app.chameleon.io/help) in your dashboard.
128
+
129
+ #### License
130
+
131
+ The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
132
+
133
+ #### Code of conduct
134
+
135
+ Everyone interacting in this project’s codebases and issue trackers is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
136
+
137
+ #### Contribution guide
138
+
139
+ Pull requests are welcome!
@@ -0,0 +1,10 @@
1
+ module Chameleon
2
+ class Config
3
+ attr_accessor :secret, :base_url, :user_agent, :use_staging
4
+
5
+ def initialize
6
+ self.base_url = 'https://api.chameleon.io'
7
+ self.user_agent = "Chameleon Ruby v#{VERSION} (chameleon.io)"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ module Chameleon
2
+ module Errors
3
+ # When a model does not have all of the required attributes
4
+ class Invalid < StandardError; end
5
+
6
+ # When the Chameleon API returns an error
7
+ #
8
+ class ApiError < StandardError
9
+ attr_reader :request, :response, :status, :body, :messages
10
+
11
+ def initialize(request, response)
12
+ @request = request
13
+ @response = response
14
+ @status = response.code
15
+ @body = JSON.parse(response.body) rescue response.body
16
+ @messages = @body['messages'].is_a?(Array) ? @body['messages'] : []
17
+
18
+ super("Chameleon API error with code: #{status}, message: #{messages[1] || 'Unknown error'}")
19
+ end
20
+ end
21
+
22
+ class AuthError < ApiError; end # 403
23
+ class NotFoundError < ApiError; end # 404
24
+ class ConflictError < ApiError; end # 409
25
+ class InputError < ApiError; end # 422
26
+ class RateLimitError < ApiError; end # 429
27
+ class ServerError < ApiError; end # 500
28
+ class TimeoutError < ApiError; end # 503
29
+
30
+ VIA_STATUS_CODE = Hash.new(ApiError)
31
+ VIA_STATUS_CODE.merge!(
32
+ 403 => AuthError,
33
+ 404 => NotFoundError,
34
+ 409 => ConflictError,
35
+ 422 => InputError,
36
+ 429 => RateLimitError,
37
+ 500 => ServerError,
38
+ 503 => TimeoutError,
39
+ )
40
+ VIA_STATUS_CODE.freeze
41
+ end
42
+ end
@@ -0,0 +1,78 @@
1
+ class Chameleon::Model
2
+ attr_accessor :id
3
+ attr_reader :attributes
4
+
5
+ def initialize(attributes={})
6
+ @attributes = {}
7
+
8
+ refresh(attributes)
9
+ end
10
+
11
+ def [](key)
12
+ @attributes[key.to_s]
13
+ end
14
+
15
+ def []=(key, value)
16
+ @attributes[key.to_s] = Chameleon::Support.value_of(value)
17
+ end
18
+
19
+ def model_name
20
+ Chameleon::Support.underscore(self.class.name.gsub('Chameleon::', ''))
21
+ end
22
+
23
+ def clear
24
+ @attributes.clear
25
+ end
26
+
27
+ def refresh(attributes)
28
+ return self unless attributes.respond_to?(:each_pair)
29
+
30
+ attributes.each_pair { |key, value| @attributes[key.to_s] = Chameleon::Support.value_of(value) }
31
+ @id = @attributes.delete('id') if @attributes.key?('id')
32
+ self
33
+ end
34
+
35
+ def url
36
+ base = "/v3/edit/#{Chameleon::Support.pluralize(model_name)}"
37
+ base << "/#{id}" if id
38
+ base
39
+ end
40
+
41
+ def create
42
+ Chameleon::Request.post(self)
43
+ end
44
+
45
+ def fetch
46
+ Chameleon::Request.get(self)
47
+ end
48
+
49
+ def delete
50
+ Chameleon::Request.delete(self)
51
+ end
52
+
53
+ def inspect
54
+ string = "#<#{self.class.name}"
55
+ string << " id=#{id}" if id
56
+ string << " attributes=#{attributes}"
57
+ string << '>'
58
+ end
59
+
60
+ private
61
+
62
+ def respond_to_missing?(symbol, other)
63
+ key = symbol.to_s
64
+ key[-1] == '=' || @attributes.key?(key)
65
+ end
66
+
67
+ def method_missing(symbol, *args)
68
+ key = symbol.to_s
69
+
70
+ if key[-1] == '=' # setter
71
+ self[key[0..-2]] = args.first
72
+ elsif @attributes.key?(key)
73
+ self[key]
74
+ else
75
+ super
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,43 @@
1
+ module Chameleon
2
+ class Company < Chameleon::Model
3
+ # https://developers.chameleon.io/#/webhooks/companies
4
+
5
+ ##
6
+ # Identify an account/Company/tenant to Chameleon
7
+ #
8
+ # @param uid The database ID for this Company (same as the uid passed to `chmln.identify` in the JS API)
9
+ # @param options Any additional user data you want Chameleon to know about
10
+ #
11
+ # @returns Chameleon::Company
12
+ #
13
+ def self.identify(uid, options={})
14
+ item = new(options.merge(uid: uid))
15
+ item.save
16
+ item
17
+ end
18
+
19
+ ##
20
+ # Retrieve an Chameleon Company
21
+ #
22
+ # @param uid The database ID for this Company (same as the uid passed to `chmln.identify` in the JS API)
23
+ #
24
+ # @returns Chameleon::Company
25
+ #
26
+ def self.fetch(uid)
27
+ item = new(uid: uid)
28
+ item.fetch
29
+ item
30
+ end
31
+
32
+ def url
33
+ path = 'v3/analyze/company'
34
+ path.gsub!(/y$/, "ies/#{id}") if id
35
+ path
36
+ end
37
+
38
+ def save
39
+ Chameleon::Request.model_request(:post, self, path: 'v3/observe/hooks/companies')
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ module Chameleon
2
+ class Deletion < Chameleon::Model
3
+ # placeholder model that will have only an `id` field
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ module Chameleon
2
+ class Event < Chameleon::Model
3
+ # https://developers.chameleon.io/#/webhooks/events
4
+
5
+ ##
6
+ # Track an Event user to Chameleon
7
+ #
8
+ # @param uid The database ID for this user (same as the uid passed to `chmln.identify` in the JS API)
9
+ # @param name The human-readable name for this event
10
+ # @param options Any additional user data you want Chameleon to know about
11
+ #
12
+ # @returns Chameleon::Event
13
+ #
14
+ def self.track(uid, name, options={})
15
+ item = new(options.merge(uid: uid, name: name))
16
+ item.save
17
+ item
18
+ end
19
+
20
+ def save
21
+ Chameleon::Request.model_request(:post, self, path: 'v3/observe/hooks/events')
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,54 @@
1
+ module Chameleon
2
+ class Profile < Chameleon::Model
3
+ # https://developers.chameleon.io/#/webhooks/profiles
4
+
5
+ ##
6
+ # Identify a user to Chameleon
7
+ #
8
+ # @param uid The database ID for this user (same as the uid passed to `chmln.identify` in the JS API)
9
+ # @param options Any additional user data you want Chameleon to know about
10
+ #
11
+ # @returns Chameleon::Profile
12
+ #
13
+ def self.identify(uid, options={})
14
+ item = new(options.merge(uid: uid))
15
+ item.save
16
+ item
17
+ end
18
+
19
+ ##
20
+ # Retrieve a Chameleon user profile
21
+ #
22
+ # @param uid The database ID for this user (same as the uid passed to `chmln.identify` in the JS API)
23
+ #
24
+ # @returns Chameleon::Profile
25
+ #
26
+ def self.fetch(uid)
27
+ item = new(uid: uid)
28
+ item.fetch
29
+ item
30
+ end
31
+
32
+ ##
33
+ # Remove this user from Chameleon and purge all of their associated data
34
+ #
35
+ # @param uid The database ID for this user (same as the uid passed to `chmln.identify` in the JS API)
36
+ # @returns Chameleon::Deletion
37
+ #
38
+ def self.forget(uid)
39
+ response = Chameleon::Request.request(:delete, 'v3/edit/profiles/forget', options: { uid: uid })
40
+ Chameleon::Deletion.new(JSON.parse(response.body)['deletion'])
41
+ end
42
+
43
+ def url
44
+ path = 'v3/analyze/profile'
45
+ path << "s/#{id}" if id
46
+ path
47
+ end
48
+
49
+ def save
50
+ Chameleon::Request.model_request(:post, self, path: 'v3/observe/hooks/profiles')
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,69 @@
1
+ module Chameleon
2
+ class SearchItem < Chameleon::Model
3
+ # https://developers.chameleon.io/#/apis/search
4
+
5
+ ##
6
+ # Add a SearchItem to the HelpBar search index
7
+ #
8
+ # @param uid The unique ID you assign for this piece of content
9
+ #
10
+ # @param options
11
+ # @param options[:title] The title of the content
12
+ # @param options[:description] The description of the content; how your user would describe it in their words
13
+ #
14
+ # @param options[:actions] An Array of the actions to take when clicking/selecting this item
15
+ #
16
+ # Content in the HelpBar can be Pinned and will display as default items when the HelpBar is first opened
17
+ #
18
+ # @param options[:pinned_at] A timestamp representing the ordering of pinned content (1.hour.ago will display above 1.day.ago)
19
+ #
20
+ # To add a specific icon to this; by default icons are inherited from the search group they are added to.
21
+ #
22
+ # @param options[:icon] The hash specifying which icon to use
23
+ # @param options[:icon][:kind] One of 'uid' or 'image'
24
+ # @param options[:icon][:uid] Required with kind=uid: The Chameleon Icon uid from the Icon library
25
+ # @param options[:icon][:image_url] Required with kind=image: The URL of an icon to use
26
+ #
27
+ # For the following params, your end-user will first be matched against these groups to build the set
28
+ # of searchable content they have access to, then the search is performed on only the filtered content.
29
+ #
30
+ # @param options[:profile_uids] The UID (your database ID) of the Chameleon User Profiles this is searchable for (same as the uid passed to `chmln.identify` in the JS API)
31
+ # @param options[:company_uids] The UID (your database ID) of the Chameleon Companies this is searchable for (same as the uid passed to `chmln.identify` in the JS API)
32
+ # @param options[:segment_ids] The ID of the Chameleon Segments this is searchable for (found on https://app.chameleon.io/segments)
33
+ #
34
+ def self.index(uid, options)
35
+ item = new(options.merge(uid: uid))
36
+ item.create
37
+ item
38
+ end
39
+
40
+ ##
41
+ # Retrieve a Chameleon Search item
42
+ #
43
+ # @param uid The unique ID you previously assigned to this piece of content
44
+ #
45
+ # @returns Chameleon::SearchItem
46
+ #
47
+ def self.fetch(uid)
48
+ item = new(uid: uid)
49
+ item.fetch
50
+ item
51
+ end
52
+
53
+ ##
54
+ # Remove the SearchItem with the given uid from the HelpBar search index
55
+ #
56
+ # @param uid The unique ID you previously assigned to this piece of content
57
+ #
58
+ def self.remove(uid)
59
+ item = new(uid: uid)
60
+ item.delete
61
+ item
62
+ end
63
+
64
+ def url
65
+ 'v3/edit/search_items'
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,64 @@
1
+ module Chameleon
2
+ class Request
3
+ def self.get(model)
4
+ raise ArgumentError, 'Fetching a Chameleon model requires at `id` or `uid`' unless model.id || model.uid
5
+
6
+ model_request :get, model, options: model.attributes.slice(*%w[uid]).compact
7
+ end
8
+
9
+ def self.post(model)
10
+ model_request :post, model
11
+ end
12
+
13
+ def self.patch(model)
14
+ model_request :patch, model
15
+ end
16
+
17
+ def self.delete(model)
18
+ model_request :delete, model, options: model.attributes.slice(*%w[uid]).compact
19
+ model.clear
20
+ model.deleted_at = Time.now
21
+ model
22
+ end
23
+
24
+ def self.model_request(method, model, options: model.attributes, path: nil)
25
+ response = request(method, path || model.url, options: options)
26
+ body = JSON.parse(response.body)
27
+
28
+ model.refresh(body[model.model_name])
29
+ model
30
+ end
31
+
32
+ def self.request(method, path, options: {})
33
+ url = "#{Chameleon.config.base_url}/#{path.gsub(/^\//, '')}"
34
+ url = staging_url(url) if Chameleon.config.use_staging
35
+ req_opts = { method: method, accept_encoding: 'gzip', headers: { 'X-Account-Secret' => Chameleon.config.secret, 'User-Agent' => Chameleon.config.user_agent } }
36
+
37
+ request = if %i[get delete].include?(method)
38
+ Typhoeus::Request.new(url, req_opts.merge(params: options))
39
+ else
40
+ req_opts[:headers]['Content-Type'] = 'application/json'
41
+
42
+ Typhoeus::Request.new(url, req_opts.merge(body: JSON.dump(options)))
43
+ end
44
+
45
+ response = request.run
46
+ error(request, response) if response.code > 300
47
+
48
+ response
49
+ end
50
+
51
+ def self.error(request, response)
52
+ raise Chameleon::Errors::VIA_STATUS_CODE[response.code].new(request, response)
53
+ end
54
+
55
+ ##
56
+ # Chameleon staging postfixes `-staging` on the environment
57
+ #
58
+ def self.staging_url(url)
59
+ env = /v3\/([^\/]+)\// =~ url && Regexp.last_match[1]
60
+
61
+ "https://#{env}-staging.#{url.split('.', 2)[1]}".gsub("/#{env}/", '/')
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,39 @@
1
+ class Chameleon::Support
2
+ def self.value_of(value)
3
+ value = case value
4
+ when Array then value.map { |v| value_of(v) }.compact
5
+ when Hash then value.dup.tap { |v| v.each_key { |k| v[k] = value_of(v[k]) } }
6
+ when String
7
+ value = value.strip
8
+
9
+ case value
10
+ when '' then nil
11
+ when /^true$/i then true
12
+ when /^false$/i then false
13
+ when '$now' then Time.now
14
+ when /^\d{4}-(0[1-9]|1[0-2])-([0-2][1-9]|[1-3]0|3[01])/ then DateTime.parse(value).to_time
15
+ when /^-?\d+\.\d+(e\d+)?$/ then value.to_f
16
+ when /^-?\d+$/ then value.to_i
17
+ else value
18
+ end
19
+ else value
20
+ end
21
+
22
+ value
23
+ end
24
+
25
+ def self.underscore(string)
26
+ string.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
27
+ string.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
28
+ string.downcase!
29
+ string
30
+ end
31
+
32
+ ##
33
+ # super naive yes, but effective for the use case here; special cases can be added if needed
34
+ #
35
+ def self.pluralize(string)
36
+ string += 's'
37
+ string
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module Chameleon
2
+ VERSION = '0.1.6'.freeze
3
+ end
data/lib/chameleon.rb ADDED
@@ -0,0 +1,23 @@
1
+ module Chameleon
2
+ autoload :VERSION, 'chameleon/version'
3
+
4
+ def self.config
5
+ @config ||= Config.new
6
+ end
7
+
8
+ def self.configure(&block)
9
+ yield config
10
+ end
11
+ end
12
+
13
+ require 'time'
14
+ require 'typhoeus'
15
+ require 'json'
16
+
17
+ require 'chameleon/config'
18
+ require 'chameleon/errors'
19
+ require 'chameleon/model'
20
+ require 'chameleon/request'
21
+ require 'chameleon/support'
22
+
23
+ Dir[File.expand_path('chameleon/models/*.rb', __dir__)].sort.each { |f| require(f) }
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chameleon-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.6
5
+ platform: ruby
6
+ authors:
7
+ - Brian Norton
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-03-23 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - brian.nort@gmail.com
16
+ - brian@chameleon.io
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE.txt
22
+ - README.md
23
+ - lib/chameleon.rb
24
+ - lib/chameleon/config.rb
25
+ - lib/chameleon/errors.rb
26
+ - lib/chameleon/model.rb
27
+ - lib/chameleon/models/company.rb
28
+ - lib/chameleon/models/deletion.rb
29
+ - lib/chameleon/models/event.rb
30
+ - lib/chameleon/models/profile.rb
31
+ - lib/chameleon/models/search_item.rb
32
+ - lib/chameleon/request.rb
33
+ - lib/chameleon/support.rb
34
+ - lib/chameleon/version.rb
35
+ homepage: https://github.com/chamaeleonidae/chameleon-ruby
36
+ licenses:
37
+ - MIT
38
+ metadata:
39
+ bug_tracker_uri: https://github.com/chamaeleonidae/chameleon-ruby/issues
40
+ changelog_uri: https://github.com/chamaeleonidae/chameleon-ruby/releases
41
+ source_code_uri: https://github.com/chamaeleonidae/chameleon-ruby
42
+ homepage_uri: https://github.com/chamaeleonidae/chameleon-ruby
43
+ rubygems_mfa_required: 'true'
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '2.6'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.4.1
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: A Ruby gem wrapper for the Chameleon REST API
63
+ test_files: []