sfkb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +106 -0
- data/bin/bundle +105 -0
- data/bin/byebug +29 -0
- data/bin/coderay +29 -0
- data/bin/console +10 -0
- data/bin/dotenv +29 -0
- data/bin/listen +29 -0
- data/bin/pry +29 -0
- data/bin/rackup +29 -0
- data/bin/rake +29 -0
- data/bin/rerun +29 -0
- data/bin/safe_yaml +29 -0
- data/bin/setup +8 -0
- data/bin/sfkb +29 -0
- data/exe/sfkb +12 -0
- data/lib/sfkb.rb +13 -0
- data/lib/sfkb/client.rb +11 -0
- data/lib/sfkb/decoration.rb +39 -0
- data/lib/sfkb/knowledge.rb +32 -0
- data/lib/sfkb/rest.rb +52 -0
- data/lib/sfkb/settings.rb +23 -0
- data/test/sfkb/client_test.rb +18 -0
- data/test/sfkb/decoration_test.rb +66 -0
- data/test/sfkb/knowledge_test.rb +48 -0
- data/test/sfkb/rest_test.rb +57 -0
- data/test/sfkb/settings_test.rb +30 -0
- data/test/sfkb_test.rb +17 -0
- data/test/test_helper.rb +22 -0
- metadata +286 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0fe296d4e57e23a2b3b1aa70da575f8fec6e8d5d7b0584e46209b202af5fcb36
|
4
|
+
data.tar.gz: 11771d874f39e8a1f80cd98ce90f578cbf7d8c0d3653f9c10981725cb542922a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3bb0f074fd40c5fc50ec0696c7d8b5de4d846571cf48921aabe889ab994adac32702f342ba9e2a4fb57e47ca4ba6f45b84750f1861bfd87e51bcb64a107d9655
|
7
|
+
data.tar.gz: dd1f38d22b8a373491f7a3c72b3d6ddad8be5794574368e529a493761ece1c2dd51f5ac74c8a5240794cf1de8af9e89b7d0d7ba4d8f1f5cfb4133a8441013a2a
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 JJ Buckley
|
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,106 @@
|
|
1
|
+
# SFKB
|
2
|
+
|
3
|
+
SalesForce Knowledge Base
|
4
|
+
|
5
|
+
A Ruby library that extends [Restforce][] to provide convenient access to
|
6
|
+
Articles and ArticlesVersions in the Salesforce Knowledge Base.
|
7
|
+
|
8
|
+
[![Build Status](https://travis-ci.org/bjjb/sfkb.svg?branch=master)](https://travis-ci.org/bjjb/sfkb)
|
9
|
+
|
10
|
+
## Requirements
|
11
|
+
|
12
|
+
- [Ruby][]
|
13
|
+
- [SalesForce][]
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
gem install sfkb
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Include it in your project, for example in your Gemfile
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'sfkb'
|
25
|
+
```
|
26
|
+
|
27
|
+
or just require it.
|
28
|
+
|
29
|
+
Now you can use the module as a client, or do something fancier by
|
30
|
+
instantiating a `SFKB::Client`.
|
31
|
+
|
32
|
+
For example, here's how to print the titles of the master versions of the
|
33
|
+
first 10 documents:
|
34
|
+
|
35
|
+
```
|
36
|
+
require 'sfkb'
|
37
|
+
SFKB.new.articles.take(10).each { |a| puts a.OnlineMasterVersion.data.Title }
|
38
|
+
```
|
39
|
+
|
40
|
+
Here's how to list the titles of every translation of every draft article:
|
41
|
+
```
|
42
|
+
sf = SFKB.new
|
43
|
+
sf.articles.select(:hasTranslations?) do |a|
|
44
|
+
sf.translations(a, 'Draft').each do |t|
|
45
|
+
puts t.data.Title
|
46
|
+
end
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Documentation is available [here][docs].
|
51
|
+
|
52
|
+
You will need to register an app in your Salesforce instance so you can obtain
|
53
|
+
your `SALESFORCE_CLIENT_ID` and `SALESFORCE_CLIENT_SECRET` (see below).
|
54
|
+
|
55
|
+
## Contributing
|
56
|
+
|
57
|
+
Bug reports and pull requests are welcome on GitHub at
|
58
|
+
https://github.com/bjjb/sfkb. This project is intended to be a safe,
|
59
|
+
welcoming space for collaboration, and contributors are expected to adhere to
|
60
|
+
the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
61
|
+
|
62
|
+
## Testing
|
63
|
+
|
64
|
+
When testing, you'll want to preconfigure your environment with these
|
65
|
+
settings:
|
66
|
+
|
67
|
+
- `SALESFORCE_CLIENT_ID`
|
68
|
+
- `SALESFORCE_CLIENT_SECRET`
|
69
|
+
|
70
|
+
You might also want to set the following (which defaults to
|
71
|
+
'login.salesforce.com) to something like 'company.my.salesforce.com', or
|
72
|
+
'test.salesforce.com' if you want to use a sandbox.
|
73
|
+
|
74
|
+
- `SALESFORCE_HOST`
|
75
|
+
|
76
|
+
For authentication, you may either use the username/password/token-secret
|
77
|
+
combination:
|
78
|
+
|
79
|
+
- `SALESFORCE_USERNAME`
|
80
|
+
- `SALESFORCE_PASSWORD`
|
81
|
+
- `SALESFORCE_SECURITY_TOKEN`
|
82
|
+
|
83
|
+
or
|
84
|
+
|
85
|
+
- `SALESFORCE_OAUTH_TOKEN`
|
86
|
+
- `SALESFORCE_REFRESH_TOKEN`
|
87
|
+
|
88
|
+
the latter of which is optional, and can (and probably should) be set using
|
89
|
+
the [`authentication_callback`][1]. For more details, see [Restforce][].
|
90
|
+
|
91
|
+
## License
|
92
|
+
|
93
|
+
The gem is available as open source under the terms of the [MIT
|
94
|
+
License](https://opensource.org/licenses/MIT).
|
95
|
+
|
96
|
+
## Code of Conduct
|
97
|
+
|
98
|
+
Everyone interacting in the Glinga project’s codebases, issue trackers, chat
|
99
|
+
rooms and mailing lists is expected to follow the [code of
|
100
|
+
conduct](https://gitlab.com/bjjb/glinga/blob/master/CODE_OF_CONDUCT.md).
|
101
|
+
|
102
|
+
[Restforce]: https://github.com/restforce/restforce
|
103
|
+
[Ruby]: https://ruby-lang.org
|
104
|
+
[Salesforce]: https://salesforce.com
|
105
|
+
[docs]: http://www.rubydoc.info/github/bjjb/sfkb
|
106
|
+
[1]: https://github.com/restforce/restforce#oauth-token-authentication
|
data/bin/bundle
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'bundle' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "rubygems"
|
12
|
+
|
13
|
+
m = Module.new do
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def invoked_as_script?
|
17
|
+
File.expand_path($0) == File.expand_path(__FILE__)
|
18
|
+
end
|
19
|
+
|
20
|
+
def env_var_version
|
21
|
+
ENV["BUNDLER_VERSION"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def cli_arg_version
|
25
|
+
return unless invoked_as_script? # don't want to hijack other binstubs
|
26
|
+
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
|
27
|
+
bundler_version = nil
|
28
|
+
update_index = nil
|
29
|
+
ARGV.each_with_index do |a, i|
|
30
|
+
if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
|
31
|
+
bundler_version = a
|
32
|
+
end
|
33
|
+
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
|
34
|
+
bundler_version = $1 || ">= 0.a"
|
35
|
+
update_index = i
|
36
|
+
end
|
37
|
+
bundler_version
|
38
|
+
end
|
39
|
+
|
40
|
+
def gemfile
|
41
|
+
gemfile = ENV["BUNDLE_GEMFILE"]
|
42
|
+
return gemfile if gemfile && !gemfile.empty?
|
43
|
+
|
44
|
+
File.expand_path("../../Gemfile", __FILE__)
|
45
|
+
end
|
46
|
+
|
47
|
+
def lockfile
|
48
|
+
lockfile =
|
49
|
+
case File.basename(gemfile)
|
50
|
+
when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
|
51
|
+
else "#{gemfile}.lock"
|
52
|
+
end
|
53
|
+
File.expand_path(lockfile)
|
54
|
+
end
|
55
|
+
|
56
|
+
def lockfile_version
|
57
|
+
return unless File.file?(lockfile)
|
58
|
+
lockfile_contents = File.read(lockfile)
|
59
|
+
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
|
60
|
+
Regexp.last_match(1)
|
61
|
+
end
|
62
|
+
|
63
|
+
def bundler_version
|
64
|
+
@bundler_version ||= begin
|
65
|
+
env_var_version || cli_arg_version ||
|
66
|
+
lockfile_version || "#{Gem::Requirement.default}.a"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def load_bundler!
|
71
|
+
ENV["BUNDLE_GEMFILE"] ||= gemfile
|
72
|
+
|
73
|
+
# must dup string for RG < 1.8 compatibility
|
74
|
+
activate_bundler(bundler_version.dup)
|
75
|
+
end
|
76
|
+
|
77
|
+
def activate_bundler(bundler_version)
|
78
|
+
if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
|
79
|
+
bundler_version = "< 2"
|
80
|
+
end
|
81
|
+
gem_error = activation_error_handling do
|
82
|
+
gem "bundler", bundler_version
|
83
|
+
end
|
84
|
+
return if gem_error.nil?
|
85
|
+
require_error = activation_error_handling do
|
86
|
+
require "bundler/version"
|
87
|
+
end
|
88
|
+
return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
89
|
+
warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
|
90
|
+
exit 42
|
91
|
+
end
|
92
|
+
|
93
|
+
def activation_error_handling
|
94
|
+
yield
|
95
|
+
nil
|
96
|
+
rescue StandardError, LoadError => e
|
97
|
+
e
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
m.load_bundler!
|
102
|
+
|
103
|
+
if m.invoked_as_script?
|
104
|
+
load Gem.bin_path("bundler", "bundle")
|
105
|
+
end
|
data/bin/byebug
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'byebug' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("byebug", "byebug")
|
data/bin/coderay
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'coderay' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("coderay", "coderay")
|
data/bin/console
ADDED
data/bin/dotenv
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'dotenv' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("dotenv", "dotenv")
|
data/bin/listen
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'listen' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("listen", "listen")
|
data/bin/pry
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'pry' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("pry", "pry")
|
data/bin/rackup
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rackup' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rack", "rackup")
|
data/bin/rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rake", "rake")
|
data/bin/rerun
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rerun' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rerun", "rerun")
|
data/bin/safe_yaml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'safe_yaml' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("safe_yaml", "safe_yaml")
|
data/bin/setup
ADDED
data/bin/sfkb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'sfkb' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("sfkb", "sfkb")
|
data/exe/sfkb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'sfkb'
|
4
|
+
|
5
|
+
begin
|
6
|
+
h = SFKB.new.authenticate!
|
7
|
+
puts 'Everything seems OK... here is an access token'
|
8
|
+
puts h.access_token
|
9
|
+
rescue
|
10
|
+
puts "Error contacting Salesforce. Check your credentials. See here:"
|
11
|
+
puts "https://github.com/bjjb/sfkb"
|
12
|
+
end
|
data/lib/sfkb.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'restforce'
|
2
|
+
require 'dotenv/load'
|
3
|
+
|
4
|
+
# A helper library for using the Salesforce Knowledge base in Ruby.
|
5
|
+
module SFKB
|
6
|
+
autoload :Knowledge, 'sfkb/knowledge'
|
7
|
+
autoload :Client, 'sfkb/client'
|
8
|
+
autoload :REST, 'sfkb/rest'
|
9
|
+
|
10
|
+
def self.new(*args)
|
11
|
+
Client.new(*args)
|
12
|
+
end
|
13
|
+
end
|
data/lib/sfkb/client.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'restforce/data/client'
|
2
|
+
require 'sfkb/rest'
|
3
|
+
require 'sfkb/knowledge'
|
4
|
+
|
5
|
+
# An SFKB::Client is an object with a connection to salesforce that can lookup
|
6
|
+
# KnowledgeArticles and KnowledgeArticleVersions using the Salesforce REST
|
7
|
+
# API.
|
8
|
+
class SFKB::Client < Restforce::Data::Client
|
9
|
+
include SFKB::REST
|
10
|
+
include SFKB::Knowledge
|
11
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SFKB
|
2
|
+
# Methods to smartly apply singleton methods to REST objects
|
3
|
+
module Decoration
|
4
|
+
def decorate(object)
|
5
|
+
return object unless block_given?
|
6
|
+
yield object
|
7
|
+
object
|
8
|
+
end
|
9
|
+
|
10
|
+
def define_link(object, name, url, &block)
|
11
|
+
getter = -> (url) { get(url).body }
|
12
|
+
decorator = -> (o) { decorate(o, &block) }
|
13
|
+
object.define_singleton_method(name) { decorator.call(getter.call(url)) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def define_links(object, urls, &block)
|
17
|
+
urls.each { |k, v| define_link(object, k, v, &block) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_predicate(object, name, value)
|
21
|
+
object.define_singleton_method(:"#{name}?") { value }
|
22
|
+
end
|
23
|
+
|
24
|
+
def autodefine(object)
|
25
|
+
return unless object.respond_to?(:additionalInformation)
|
26
|
+
return unless info = object.additionalInformation
|
27
|
+
info.each do |k, v|
|
28
|
+
if [true, false].include?(v)
|
29
|
+
define_predicate(object, k, v)
|
30
|
+
elsif k.to_s == 'data'
|
31
|
+
define_link(object, :data, v)
|
32
|
+
elsif k.to_s == 'urls'
|
33
|
+
define_links(object, v) { |o| autodefine(o) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
object
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'sfkb/rest'
|
2
|
+
require 'sfkb/settings'
|
3
|
+
require 'sfkb/decoration'
|
4
|
+
|
5
|
+
module SFKB
|
6
|
+
module Knowledge
|
7
|
+
include REST
|
8
|
+
include Settings
|
9
|
+
include Decoration
|
10
|
+
|
11
|
+
# Queries for all (undeleted) article IDs, returning an array.
|
12
|
+
def article_ids
|
13
|
+
query('SELECT Id FROM KnowledgeArticle').map(&:Id)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Enumerates articles
|
17
|
+
def articles
|
18
|
+
Enumerator.new do |y|
|
19
|
+
article_ids.each do |id|
|
20
|
+
y << article(id)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Gets an article by ID
|
26
|
+
def article(id)
|
27
|
+
url = index.knowledgeManagement.articles.article
|
28
|
+
url = url(url, ArticleID: id)
|
29
|
+
decorate(get(url).body) { |o| autodefine(o) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/sfkb/rest.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module SFKB
|
2
|
+
# Some REST helpers
|
3
|
+
module REST
|
4
|
+
# Used to interpolate variables into REST endpoint URIs
|
5
|
+
@@placeholder = /[<{](.+?)[>}]/
|
6
|
+
|
7
|
+
# { a: :b }.inject({}, &@@stringify) #=> { 'a' => :b }
|
8
|
+
@@stringify = lambda do |collector, kv|
|
9
|
+
collector.tap { |h| h[kv[0].to_s] = kv[1] }
|
10
|
+
end
|
11
|
+
|
12
|
+
# { a: 1 }.delete(:b, &@@required) # raises 'missing param: b'
|
13
|
+
@@required = -> (s) { raise(ArgumentError, "missing param: <#{s}>") }
|
14
|
+
|
15
|
+
# { a: b, c: d }.inject('x', &@@parameterize) #=> 'x?a=b&c=d'
|
16
|
+
@@parameterize = lambda do |s, kv|
|
17
|
+
k, *vs = *kv
|
18
|
+
params = vs.flatten.map { |v| [k, v].join('=') }
|
19
|
+
[s, params].flatten.compact.reject(&:empty?).join('&')
|
20
|
+
end
|
21
|
+
|
22
|
+
# Converts a path and params to a Salesforce-suitable URL.
|
23
|
+
def url(path, params = {})
|
24
|
+
params = params.inject({}, &@@stringify)
|
25
|
+
path = path.gsub(@@placeholder) { params.delete($1, &@@required) }
|
26
|
+
params = params.inject('', &@@parameterize)
|
27
|
+
[path, params].reject(&:nil?).reject(&:empty?).join('?')
|
28
|
+
end
|
29
|
+
|
30
|
+
# The REST API starts here
|
31
|
+
def index
|
32
|
+
endpoint("/services/data/v#{options[:api_version]}") do |k, v|
|
33
|
+
endpoint(v) { |k, v| endpoint(v) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Fetches the object at url, and extends it with methods
|
38
|
+
def endpoint(url)
|
39
|
+
get(url).body.tap do |o|
|
40
|
+
o.each do |k, v|
|
41
|
+
o.define_singleton_method(k) do
|
42
|
+
ivar = :"@#{k}"
|
43
|
+
return instance_variable_get(ivar) if instance_variable_defined?(ivar)
|
44
|
+
instance_variable_set(ivar, block_given? ? yield(k, v) : v)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
extend self
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SFKB
|
2
|
+
# Methods for getting Salesforce Knowledge settings. Mix it into something
|
3
|
+
# with an index.
|
4
|
+
module Settings
|
5
|
+
# Tells the default language
|
6
|
+
def defaultLanguage
|
7
|
+
settings.defaultLanguage
|
8
|
+
end
|
9
|
+
|
10
|
+
# The list of languages
|
11
|
+
def languages
|
12
|
+
settings.languages
|
13
|
+
end
|
14
|
+
|
15
|
+
def active_languages
|
16
|
+
settings.languages.select(&:active).map(&:name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def settings
|
20
|
+
index.knowledgeManagement.settings
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'sfkb'
|
3
|
+
|
4
|
+
describe SFKB::Client do
|
5
|
+
let(:client) { SFKB::Client.new }
|
6
|
+
|
7
|
+
it 'is a Restforce of nature' do
|
8
|
+
assert SFKB::Client < Restforce::Data::Client
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'knows how to REST' do
|
12
|
+
assert SFKB::Client < SFKB::REST
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'has great Knowledge' do
|
16
|
+
assert SFKB::Client < SFKB::Knowledge
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'sfkb/decoration'
|
3
|
+
|
4
|
+
describe SFKB::Decoration do
|
5
|
+
include SFKB::Decoration
|
6
|
+
|
7
|
+
describe 'decorate(String)' do
|
8
|
+
it 'returns the string' do
|
9
|
+
assert_equal 'a', decorate('a')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'yields the string' do
|
13
|
+
decorate('a') do |x|
|
14
|
+
assert_equal 'a', x
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'decorate({x: y})' do
|
20
|
+
it 'returns the hash' do
|
21
|
+
assert_equal({ x: :y }, decorate(x: :y))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'define_link(obj, name, url)' do
|
26
|
+
it 'defines a getter method for the link' do
|
27
|
+
foo = 'hi'
|
28
|
+
define_singleton_method(:get) { |x| OpenStruct.new(body: 'Found me') }
|
29
|
+
define_link(foo, 'bar', '/baz')
|
30
|
+
assert_respond_to foo, :bar
|
31
|
+
assert_equal "Found me", foo.bar
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'define_predicate(obj, name, value)' do
|
36
|
+
it 'defines a predicate method for value' do
|
37
|
+
foo = 'hi'
|
38
|
+
define_predicate(foo, 'bar', true)
|
39
|
+
define_predicate(foo, 'baz', false)
|
40
|
+
assert foo.bar?
|
41
|
+
refute foo.baz?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'define_links(obj, { a: "/l1", b: "/l2" })' do
|
46
|
+
it 'links all urls to those names' do
|
47
|
+
foo = 'hi'
|
48
|
+
define_links(foo, { a: '/l1', b: '/l2' })
|
49
|
+
define_singleton_method(:get) { |x| OpenStruct.new(body: "I was at #{x}!") }
|
50
|
+
assert_equal 'I was at /l1!', foo.a
|
51
|
+
assert_equal 'I was at /l2!', foo.b
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'autodefine' do
|
56
|
+
let(:foo) { OpenStruct.new(additionalInformation: { isTall: true, isFat: false, urls: { a: '/l1' }, data: '/l3' }) }
|
57
|
+
it 'uses additionalInformation' do
|
58
|
+
define_singleton_method(:get) { |x| OpenStruct.new(body: "I was at #{x}!") }
|
59
|
+
autodefine(foo)
|
60
|
+
assert foo.isTall?
|
61
|
+
refute foo.isFat?
|
62
|
+
assert_equal 'I was at /l1!', foo.a
|
63
|
+
assert_equal 'I was at /l3!', foo.data
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'hipsterhash'
|
3
|
+
require 'sfkb/knowledge'
|
4
|
+
|
5
|
+
describe SFKB::Knowledge do
|
6
|
+
let(:subject) { klass.new }
|
7
|
+
|
8
|
+
let(:klass) do
|
9
|
+
Class.new(Minitest::Mock) do
|
10
|
+
include SFKB::Knowledge
|
11
|
+
define_method(:index) do
|
12
|
+
HipsterHash.new.tap do |hh|
|
13
|
+
hh[:knowledgeManagement] = {
|
14
|
+
articles: {
|
15
|
+
article: '/articles/<ArticleID>'
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:ids) { %w(1 2 3).map { |id| Struct.new(:Id).new(id) } }
|
24
|
+
|
25
|
+
describe 'article_ids' do
|
26
|
+
it 'gets a list of article IDs' do
|
27
|
+
subject.expect(:query, ids, [/KnowledgeArticle/])
|
28
|
+
assert_equal %w(1 2 3), subject.article_ids
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'articles' do
|
33
|
+
it 'gets all articles based on the article_ids' do
|
34
|
+
subject.expect(:query, ids, [/KnowledgeArticle/])
|
35
|
+
subject.expect(:get, Struct.new(:body).new('a'), ['/articles/1'])
|
36
|
+
subject.expect(:get, Struct.new(:body).new('b'), ['/articles/2'])
|
37
|
+
subject.expect(:get, Struct.new(:body).new('c'), ['/articles/3'])
|
38
|
+
assert_equal %w(a b c), subject.articles.to_a
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'article' do
|
43
|
+
it 'gets a particular article' do
|
44
|
+
subject.expect(:get, Struct.new(:body).new('a'), ['/articles/1'])
|
45
|
+
assert_equal 'a', subject.article(1)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'sfkb/rest'
|
3
|
+
|
4
|
+
describe SFKB::REST do
|
5
|
+
let(:klass) { Class.new(Minitest::Mock) { include SFKB::REST } }
|
6
|
+
let(:subject) { klass.new }
|
7
|
+
let(:response) { |x| OpenStruct.new(body: x) }
|
8
|
+
|
9
|
+
describe 'url' do
|
10
|
+
it 'joins paths to params amd substitutes vars' do
|
11
|
+
assert_equal '/foo', subject.url('/foo')
|
12
|
+
assert_equal '/foo?x=1', subject.url('/foo', x: 1)
|
13
|
+
assert_equal '/foo?x=1&y=2', subject.url('/foo', x: 1, y: 2)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'substitutes vars' do
|
17
|
+
assert_equal '/foo/1/2', subject.url('/foo/<x>/<y>', x: 1, y: 2)
|
18
|
+
assert_equal '/foo/1?y=2', subject.url('/foo/<x>', x: 1, y: 2)
|
19
|
+
assert_equal '/foo/1?b=2&b=3&c=4',
|
20
|
+
subject.url('/foo/<a>', a: 1, b: %w(2 3), c: 4)
|
21
|
+
assert_raises { subject.url('/foo/<blah>') }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'index' do
|
26
|
+
let(:index) { subject.index }
|
27
|
+
|
28
|
+
before do
|
29
|
+
subject.expect(:options, { api_version: 'X' })
|
30
|
+
subject.expect(:get, OpenStruct.new(body: { a: '/a' }), ['/services/data/vX'])
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'looks up the index for the current api version' do
|
34
|
+
index
|
35
|
+
subject.verify
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'is a whatever was returned, hopefully a hash' do
|
39
|
+
assert_equal({ a: '/a' }, index)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'adds endpoints for the url values of the hash' do
|
43
|
+
subject.expect(:get, OpenStruct.new(body: { b: '/b', c: '/c' }), ['/a'])
|
44
|
+
assert_equal({ b: '/b', c: '/c'}, index.a)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'adds endpoints for the subresource' do
|
48
|
+
subject.expect(:get, OpenStruct.new(body: { b: '/b', c: '/c' }), ['/a'])
|
49
|
+
subject.expect(:get, OpenStruct.new(body: { d: '/d', e: '/e' }), ['/b'])
|
50
|
+
subject.expect(:get, OpenStruct.new(body: { f: '/f', g: '/g' }), ['/c'])
|
51
|
+
assert_equal '/d', index.a.b.d
|
52
|
+
assert_equal '/e', index.a.b.e
|
53
|
+
assert_equal '/f', index.a.c.f
|
54
|
+
assert_equal '/g', index.a.c.g
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'sfkb/settings'
|
3
|
+
|
4
|
+
describe SFKB::Settings do
|
5
|
+
let(:subject) { klass.new }
|
6
|
+
let(:klass) { Class.new(Minitest::Mock) { include SFKB::Settings } }
|
7
|
+
|
8
|
+
let(:index) { Minitest::Mock.new('index') }
|
9
|
+
let(:languages) { %w(zh ja en).map { |l| OpenStruct.new(name: l, active: l != 'ja') } }
|
10
|
+
let(:knowledgeManagement) { Minitest::Mock.new('knowledgeManagement') }
|
11
|
+
let(:settings) { OpenStruct.new(defaultLanguage: 'en', languages: languages) }
|
12
|
+
|
13
|
+
before do
|
14
|
+
subject.expect :index, index
|
15
|
+
index.expect :knowledgeManagement, knowledgeManagement
|
16
|
+
knowledgeManagement.expect :settings, settings
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'knows its default language' do
|
20
|
+
assert_equal 'en', subject.defaultLanguage
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'knows its languages' do
|
24
|
+
assert_equal languages, subject.languages
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'knows its active languages' do
|
28
|
+
assert_equal %w(zh en), subject.active_languages
|
29
|
+
end
|
30
|
+
end
|
data/test/sfkb_test.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'sfkb'
|
3
|
+
|
4
|
+
describe SFKB do
|
5
|
+
let(:sfkb) { SFKB.new }
|
6
|
+
|
7
|
+
it 'constructs a client' do
|
8
|
+
assert_instance_of SFKB::Client, SFKB.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'can list articles' do
|
12
|
+
assert_respond_to sfkb.articles, :each
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'an article' do
|
16
|
+
end
|
17
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start
|
5
|
+
|
6
|
+
require 'dotenv/load'
|
7
|
+
|
8
|
+
require 'vcr'
|
9
|
+
VCR.configure do |vcr|
|
10
|
+
vcr.cassette_library_dir = 'test/cassettes'
|
11
|
+
vcr.hook_into :faraday
|
12
|
+
ENV.keys.grep(/^SALESFORCE_/).each do |var|
|
13
|
+
vcr.filter_sensitive_data(var) { ENV[var] }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'minitest-vcr'
|
18
|
+
MinitestVcr::Spec.configure!
|
19
|
+
|
20
|
+
require 'pry'
|
21
|
+
|
22
|
+
require 'minitest/autorun'
|
metadata
ADDED
@@ -0,0 +1,286 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sfkb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- JJ Buckley
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: restforce
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: oauth2
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.4'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: hipsterhash
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.0.4
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.0.4
|
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.16'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.16'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '12.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '12.3'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '5.11'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '5.11'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: dotenv
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.2'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.2'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: faraday
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.12'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.12'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: vcr
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '4.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '4.0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: minitest-vcr
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '1.4'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '1.4'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: pry
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0.11'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0.11'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: byebug
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "~>"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '10.0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '10.0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: pry-byebug
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '3.6'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '3.6'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: rack-test
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - "~>"
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0.8'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0.8'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: simplecov
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - "~>"
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0.15'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - "~>"
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0.15'
|
223
|
+
description: |
|
224
|
+
A Ruby library (based on Restforce) for working with the Salesforce Knowledge
|
225
|
+
Base.
|
226
|
+
email:
|
227
|
+
- jj@bjjb.org
|
228
|
+
executables:
|
229
|
+
- sfkb
|
230
|
+
extensions: []
|
231
|
+
extra_rdoc_files: []
|
232
|
+
files:
|
233
|
+
- LICENSE.txt
|
234
|
+
- README.md
|
235
|
+
- bin/bundle
|
236
|
+
- bin/byebug
|
237
|
+
- bin/coderay
|
238
|
+
- bin/console
|
239
|
+
- bin/dotenv
|
240
|
+
- bin/listen
|
241
|
+
- bin/pry
|
242
|
+
- bin/rackup
|
243
|
+
- bin/rake
|
244
|
+
- bin/rerun
|
245
|
+
- bin/safe_yaml
|
246
|
+
- bin/setup
|
247
|
+
- bin/sfkb
|
248
|
+
- exe/sfkb
|
249
|
+
- lib/sfkb.rb
|
250
|
+
- lib/sfkb/client.rb
|
251
|
+
- lib/sfkb/decoration.rb
|
252
|
+
- lib/sfkb/knowledge.rb
|
253
|
+
- lib/sfkb/rest.rb
|
254
|
+
- lib/sfkb/settings.rb
|
255
|
+
- test/sfkb/client_test.rb
|
256
|
+
- test/sfkb/decoration_test.rb
|
257
|
+
- test/sfkb/knowledge_test.rb
|
258
|
+
- test/sfkb/rest_test.rb
|
259
|
+
- test/sfkb/settings_test.rb
|
260
|
+
- test/sfkb_test.rb
|
261
|
+
- test/test_helper.rb
|
262
|
+
homepage: https://github.com/bjjb/sfkb
|
263
|
+
licenses:
|
264
|
+
- MIT
|
265
|
+
metadata: {}
|
266
|
+
post_install_message:
|
267
|
+
rdoc_options: []
|
268
|
+
require_paths:
|
269
|
+
- lib
|
270
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
271
|
+
requirements:
|
272
|
+
- - ">="
|
273
|
+
- !ruby/object:Gem::Version
|
274
|
+
version: '0'
|
275
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
276
|
+
requirements:
|
277
|
+
- - ">="
|
278
|
+
- !ruby/object:Gem::Version
|
279
|
+
version: '0'
|
280
|
+
requirements: []
|
281
|
+
rubyforge_project:
|
282
|
+
rubygems_version: 2.7.3
|
283
|
+
signing_key:
|
284
|
+
specification_version: 4
|
285
|
+
summary: SalesForce Knowledge Base helper library
|
286
|
+
test_files: []
|