marketo-api-ruby 0.8

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.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NjY4NjRlOGQ0YjY2MWNmY2QwNDQyNmM3YTA2NTJlNzcxNmRiZTNiOA==
5
+ data.tar.gz: !binary |-
6
+ YWNhZjY4NGU3ZTE5YTVhZTY2Y2IyOTZmMGI4MTUyZTJmODg0MzFmZg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MGYzYjBkODBjOTE1MDRmYmYxMmNhMjQyMDU0MmI2NGQwZTdhNGViM2Q1ODAx
10
+ NWU4NzJmN2YwOWEwYmRiM2EzMWQzZGRiNzRlNTZhMjNkZjY1ZmFkMTZiOGQz
11
+ YmVjYzJiYjMxZGY5ZTVlODRlODQwOGVmMTI1Y2RmNmQwMGNjYzM=
12
+ data.tar.gz: !binary |-
13
+ ZGNiMmEwYTU3NGE3MmE3NWE3NGI3Nzc5OWY3M2MxYWQwZDU1Njc3ZjRiZTc5
14
+ YTA0MDZiNTEyMTA2MjYzNjhjYTFiMWVlYjAzNmJjMzZhNmI0NGZhYTk3YTRh
15
+ N2NlY2Y3ZjM3ZDFmYWYzMTU1ZGI5NzNhMTZmY2I4YjcwMDNiNGE=
Binary file
@@ -0,0 +1,2 @@
1
+ ^ �޼p��'*h⻖�2xX��"8��Qb���a� �ܑa�mٺ�$�s���OfB�~�.q_�`Ԗ=���!�$b�bGރ��n,l B�ndD�O��E��������G�z]}��P@��LM���n��rO�e�j�3�)��^'���2o�ɤmra
2
+ �׆����C��>�C�nc*3�C~qs�j��7�平��TXg�!)B��Hb�b��������a_ڌI�[� ��8��s��iG����.�c<t����
File without changes
@@ -0,0 +1,65 @@
1
+ == Contributing
2
+
3
+ I value any contribution to marketo-api-ruby you can provide: a bug report, a
4
+ feature request, or code contributions. Here are a few guidelines:
5
+
6
+ * Code changes *will* *not* be accepted without tests. The test suite is
7
+ written with {Minitest}[https://github.com/seattlerb/minitest].
8
+ * Match my coding style.
9
+ * Use a thoughtfully-named topic branch that contains your change. Rebase your
10
+ commits into logical chunks as necessary.
11
+ * Use {quality commit messages}[http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html].
12
+ * Do not change the version number; when your patch is accepted and a release
13
+ is made, the version will be updated at that point.
14
+ * Submit a GitHub pull request with your changes.
15
+ * New or changed behaviours require new or updated documentation.
16
+
17
+ === Test Dependencies
18
+
19
+ marketo-api-ruby uses Ryan Davis’s {Hoe}[https://github.com/seattlerb/hoe] to
20
+ manage the release process, and it adds a number of rake tasks. You will mostly
21
+ be interested in:
22
+
23
+ $ rake
24
+
25
+ which runs the tests the same way that:
26
+
27
+ $ rake test
28
+ $ rake travis
29
+
30
+ will do.
31
+
32
+ To assist with the installation of the development dependencies for
33
+ marketo-api-ruby, I have provided the simplest possible Gemfile pointing to the
34
+ (generated) +marketo-api-ruby.gemspec+ file. This will permit you to do:
35
+
36
+ $ bundle install
37
+
38
+ to get the development dependencies. If you aleady have +hoe+ installed, you
39
+ can accomplish the same thing with:
40
+
41
+ $ rake newb
42
+
43
+ This task will install any missing dependencies, run the tests/specs, and
44
+ generate the RDoc.
45
+
46
+ === Workflow
47
+
48
+ Here's the most direct way to get your work merged into the project:
49
+
50
+ * Fork the project.
51
+ * Clone down your fork (<tt>git clone git://github.com/<username>/marketo-api-ruby.git</tt>).
52
+ * Create a topic branch to contain your change (<tt>git checkout -b my\_awesome\_feature</tt>).
53
+ * Hack away, add tests. Not necessarily in that order.
54
+ * Make sure everything still passes by running +rake+.
55
+ * If necessary, rebase your commits into logical chunks, without errors.
56
+ * Push the branch up (<tt>git push origin my\_awesome\_feature</tt>).
57
+ * Create a pull request against ClearFit/marketo-api-ruby and describe what
58
+ your change does and the why you think it should be merged.
59
+
60
+ === Contributors
61
+
62
+ * Austin Ziegler (@halostatue) created and maintains marketo-api-ruby for ClearFit.
63
+ * James O'Brien (@jeob32) created
64
+ {marketo_gem}[https://github.com/Rapleaf/marketo_gem] for Rapleaf.
65
+ * Eddie Siegel (@eddiesiegel)
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # -*- ruby -*-
2
+
3
+ # NOTE: This file is present to keep Travis CI happy. Edits to it will not
4
+ # be accepted.
5
+
6
+ source "https://rubygems.org/"
7
+ gemspec
8
+
9
+ # vim: syntax=ruby
@@ -0,0 +1,3 @@
1
+ === 0.8 / 2014-04-08
2
+
3
+ * First release as marketo-api-ruby. Features a substantially restructured API.
@@ -0,0 +1,24 @@
1
+ == Licence
2
+
3
+ This software is available under the terms of the MIT license.
4
+
5
+ * Copyright 2014 ClearFit, Inc.
6
+ * Copyright 2013 Rapleaft, Inc.
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
9
+ this software and associated documentation files (the "Software"), to deal in
10
+ the Software without restriction, including without limitation the rights to
11
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12
+ of the Software, and to permit persons to whom the Software is furnished to do
13
+ so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
@@ -0,0 +1,32 @@
1
+ .gemtest
2
+ Contributing.rdoc
3
+ Gemfile
4
+ History.rdoc
5
+ Licence.rdoc
6
+ Manifest.txt
7
+ README.rdoc
8
+ Rakefile
9
+ lib/marketo-api-ruby.rb
10
+ lib/marketo_api.rb
11
+ lib/marketo_api/campaigns.rb
12
+ lib/marketo_api/client.rb
13
+ lib/marketo_api/client_proxy.rb
14
+ lib/marketo_api/lead.rb
15
+ lib/marketo_api/leads.rb
16
+ lib/marketo_api/lists.rb
17
+ lib/marketo_api/mobject.rb
18
+ lib/marketo_api/mobjects.rb
19
+ spec/marketo/authentication_header_spec.rb
20
+ spec/marketo/client_spec.rb
21
+ spec/marketo/lead_key_spec.rb
22
+ spec/marketo/lead_record_spec.rb
23
+ spec/spec_helper.rb
24
+ test/marketo_api/test_campaigns.rb
25
+ test/marketo_api/test_client.rb
26
+ test/marketo_api/test_lead.rb
27
+ test/marketo_api/test_leads.rb
28
+ test/marketo_api/test_lists.rb
29
+ test/marketo_api/test_mobject.rb
30
+ test/marketo_api/test_mobjects.rb
31
+ test/minitest_helper.rb
32
+ test/test_marketo_api.rb
@@ -0,0 +1,105 @@
1
+ = marketo-api-ruby
2
+
3
+ home :: https://github.com/ClearFit/marketo-api-ruby
4
+ code :: https://github.com/ClearFit/marketo-api-ruby
5
+ bugs :: https://github.com/ClearFit/marketo-api-ruby/issues
6
+ rdoc :: https://rdoc.info/gems/marketo-api-ruby
7
+ continuous integration :: {<img src="https://travis-ci.org/ClearFit/marketo-api-ruby.png" />}[https://travis-ci.org/ClearFit/marketo-api-ruby]
8
+ test coverage :: {<img src="https://coveralls.io/repos/ClearFit/marketo-api-ruby/badge.png" alt="Coverage Status" />}[https://coveralls.io/r/ClearFit/marketo-api-ruby]
9
+
10
+ == Description
11
+
12
+ MarketoAPI (marketo-api-ruby) provides a native Ruby interface to the
13
+ {Marketo SOAP API}[http://developers.marketo.com/documentation/soap/], using
14
+ {savon}[https://github.com/savonrb/savon]. While understanding the Marketo SOAP
15
+ API is necessary for using marketo-api-ruby, it is an explicit goal that
16
+ working with MarketoAPI not feel like working with a hinky Java port.
17
+
18
+ This is release 0.8, targeting Marketo API version
19
+ {2.3}[http://app.marketo.com/soap/mktows/2_3?WSDL].
20
+
21
+ === Features/Problems
22
+
23
+ The marketo-api-ruby implementation of the Marketo SOAP API is incomplete, but
24
+ is scheduled to be complete against Marketo SOAP API 2.3 for the version 1.0
25
+ release; this will take some time.
26
+
27
+ - Marketo Object (MObject) operations are 80% implemented.
28
+ - Not implemented: +syncMObjects+
29
+ - Improvements will be made to the criteria-building interface and the
30
+ association-building interface.
31
+ - Marketo Custom Object operations are not yet implemented.
32
+ - Marketo Lead operations are 37% implemented.
33
+ - Not implemented: +getMultipleLeads+, +mergeLeads+, +getLeadActivity+,
34
+ +getLeadChanges+
35
+ - Marketo Campaign operations are 90% implemented.
36
+ - The +requestCampaign+ API is currently awkward around managing program
37
+ tokens (+programTokenList+ in the SOAP API).
38
+ - The +scheduleCampaign+ API is currently awkward around managing program
39
+ tokens (+programTokenList+ in the SOAP API).
40
+ - Marketo List opertions are 100% implemented.
41
+
42
+ == Synopsis
43
+
44
+ require 'marketo_api' # Only required if not loaded by Bundler
45
+ marketo = MarketoAPI.client(
46
+ api_subdomain: '123-ABC-456',
47
+ user_id: 'my-api-user-id',
48
+ encryption_key: 'my-api-encryption-key'
49
+ )
50
+
51
+ # Get a lead by email, and sync it back to Marketo.
52
+ lead = marketo.leads.get_by_email('mork@ork.com')
53
+ lead.email = 'mindy@ork.com'
54
+ lead.sync!
55
+
56
+ # Get campaigns for marketo (MKTOWS)
57
+ puts marketo.campaigns.for_marketo
58
+
59
+ # Delete Opportunity 75.
60
+ marketo.mobjects.delete MarketoAPI::MObject.opportunity(75)
61
+
62
+ # Get all Marketo programs
63
+
64
+ == Install
65
+
66
+ Add to your application's Gemfile:
67
+
68
+ gem 'marketo-api-ruby'
69
+
70
+ Or install manually:
71
+
72
+ gem install marketo-api-ruby
73
+
74
+ == Developers
75
+
76
+ After checking out the source, run:
77
+
78
+ $ rake newb
79
+
80
+ This task will install any missing dependencies, run the tests/specs,
81
+ and generate the RDoc.
82
+
83
+ == marketo-api-ruby Modified Semantic Versioning
84
+
85
+ The marketo-api-ruby library tracks an externally versioned API; this is not
86
+ fully compatible with all aspects of {Semantic Versioning}[http://semver.org/].
87
+
88
+ 1. MAJOR versions will be updated when targeting a new major version of the
89
+ Marketo API, if Marketo makes incompatible changes to its API in minor
90
+ versions, *or* when incompatible marketo-api-ruby API changes are made. The
91
+ release notes will identify the cause of the update.
92
+ 2. MINOR versions will be updated when targeting a new minor version of the
93
+ Marketo API (e.g., Marketo version 2.2 to 2.3).
94
+ 3. PATCH version when backwards-compatible bug fixes are made.
95
+
96
+ Additionally, each release will clearly identify which Marketo API it targets
97
+ as its baseline. If a release is made without a PATCH level, it can be assumed
98
+ to be zero.
99
+
100
+ In practical terms, MAJOR versions will only be updated if you cannot use an
101
+ earlier API version for an existing query (such as +Marketo::Lead#sync+).
102
+
103
+ :include: Contributing.rdoc
104
+
105
+ :include: Licence.rdoc
@@ -0,0 +1,65 @@
1
+ # -*- ruby -*-
2
+
3
+ require "rubygems"
4
+ require "hoe"
5
+
6
+ Hoe.plugin :doofus
7
+ Hoe.plugin :gemspec2
8
+ Hoe.plugin :git
9
+ Hoe.plugin :heroku
10
+ Hoe.plugin :minitest
11
+ Hoe.plugin :travis
12
+ Hoe.plugin :email unless ENV['CI'] or ENV['TRAVIS']
13
+
14
+ spec = Hoe.spec "marketo-api-ruby" do
15
+ developer('Austin Ziegler', 'halostatue@gmail.com')
16
+ self.need_tar = false
17
+ self.require_ruby_version '>= 1.9.2'
18
+
19
+ license 'MIT'
20
+
21
+ self.history_file = 'History.rdoc'
22
+ self.readme_file = 'README.rdoc'
23
+ self.extra_rdoc_files = FileList["*.rdoc"].to_a
24
+
25
+ self.extra_deps << ['savon', '~> 2.4']
26
+
27
+ self.extra_dev_deps << ['hoe-doofus', '~> 1.0']
28
+ self.extra_dev_deps << ['hoe-gemspec2', '~> 1.1']
29
+ self.extra_dev_deps << ['hoe-git', '~> 1.6']
30
+ self.extra_dev_deps << ['hoe-rubygems', '~> 1.0']
31
+ self.extra_dev_deps << ['hoe-travis', '~> 1.2']
32
+ self.extra_dev_deps << ['minitest', '~> 5.3']
33
+ self.extra_dev_deps << ['rake', '~> 10.0']
34
+ self.extra_dev_deps << ['simplecov', '~> 0.7']
35
+ self.extra_dev_deps << ['coveralls', '~> 0.7']
36
+ end
37
+
38
+ namespace :test do
39
+ desc "Submit test coverage to Coveralls"
40
+ task :coveralls do
41
+ spec.test_prelude = [
42
+ 'require "psych"',
43
+ 'require "simplecov"',
44
+ 'require "coveralls"',
45
+ 'SimpleCov.formatter = Coveralls::SimpleCov::Formatter',
46
+ 'SimpleCov.start("test_frameworks") { command_name "Minitest" }',
47
+ 'gem "minitest"'
48
+ ].join('; ')
49
+ Rake::Task['test'].execute
50
+ end
51
+
52
+ desc "Generate a test coverage report"
53
+ task :coverage do
54
+ spec.test_prelude = [
55
+ 'require "simplecov"',
56
+ 'SimpleCov.start("test_frameworks") { command_name "Minitest" }',
57
+ 'gem "minitest"'
58
+ ].join('; ')
59
+ Rake::Task['test'].execute
60
+ end
61
+ end
62
+
63
+ Rake::Task['travis'].prerequisites.replace(%w(test:coveralls))
64
+
65
+ # vim: syntax=ruby
@@ -0,0 +1 @@
1
+ require 'marketo_api'
@@ -0,0 +1,39 @@
1
+ # MarketoAPI (marketo-api-ruby) provides a native Ruby interface to the
2
+ # {Marketo SOAP API}[http://developers.marketo.com/documentation/soap/],
3
+ # using {savon}[https://github.com/savonrb/savon].
4
+ #
5
+ # == Synopsis
6
+ #
7
+ # require 'marketo_api'
8
+ module MarketoAPI
9
+ VERSION = "0.8"
10
+
11
+ MINIMIZE_HASH = ->(k, v) { #:nodoc:
12
+ v.nil? or (v.respond_to?(:empty?) and v.empty?)
13
+ }
14
+
15
+ class << self
16
+ # Create a new MarketoAPI::Client, essentially an alias for
17
+ # MarketoAPI::Client.new.
18
+ def client(config = {})
19
+ MarketoAPI::Client.new(config)
20
+ end
21
+
22
+ def array(object) # :nodoc:
23
+ case object
24
+ when Hash
25
+ [ object ]
26
+ when Array
27
+ object
28
+ else
29
+ Kernel.Array(object)
30
+ end
31
+ end
32
+
33
+ def freeze(*args) # :nodoc:
34
+ args.each(&:freeze).freeze
35
+ end
36
+ end
37
+ end
38
+
39
+ require 'marketo_api/client'
@@ -0,0 +1,194 @@
1
+ require_relative 'client_proxy'
2
+
3
+ # Implements Campaign-related calls for Marketo.
4
+ #
5
+ # === Sources
6
+ #
7
+ # Campaigns have a source, which the Marketo SOAP API provides as +MKTOWS+
8
+ # and +SALES+. MarketoAPI provides these values as the friendlier values
9
+ # +marketo+ and +sales+, but accepts the standard Maketo SOAP API
10
+ # enumeration values.
11
+ class MarketoAPI::Campaigns < MarketoAPI::ClientProxy
12
+ SOURCES = { #:nodoc:
13
+ marketo: :MKTOWS,
14
+ sales: :SALES,
15
+ }.freeze
16
+ private_constant :SOURCES
17
+
18
+ ENUMS = MarketoAPI.freeze(*SOURCES.values) #:nodoc:
19
+ private_constant :ENUMS
20
+
21
+ # Implements
22
+ # {+getCampaignsForSource+}[http://developers.marketo.com/documentation/soap/getcampaignsforsource/].
23
+ #
24
+ # If possible, prefer the generated methods #for_marketo and #for_sales.
25
+ #
26
+ # :call-seq:
27
+ # for_source(source)
28
+ # for_source(source, name)
29
+ # for_source(source, name, exact_name)
30
+ def for_source(source, name = nil, exact_name = nil)
31
+ call(
32
+ :get_campaigns_for_source,
33
+ {
34
+ source: resolve_source(source),
35
+ name: name,
36
+ exact_name: exact_name
37
+ }.delete_if(&MarketoAPI::MINIMIZE_HASH)
38
+ )
39
+ end
40
+
41
+ ##
42
+ # :method: for_marketo
43
+ #
44
+ # Implements +getCampaignsForSource+ for the +marketo+ source; a
45
+ # specialization of #for_source.
46
+ #
47
+ # :call-seq:
48
+ # for_marketo()
49
+ # for_marketo(name)
50
+ # for_marketo(name, exact_name)
51
+
52
+ ##
53
+ # :method: for_sales
54
+ #
55
+ # Implements +getCampaignsForSource+ for the +sales+ source; a
56
+ # specialization of #for_source.
57
+ #
58
+ # :call-seq:
59
+ # for_sales()
60
+ # for_sales(name)
61
+ # for_sales(name, exact_name)
62
+
63
+ # Implements
64
+ # {+requestCampaign+}[http://developers.marketo.com/documentation/soap/requestcampaign/].
65
+ #
66
+ # === Parameters
67
+ #
68
+ # +source+:: Required. The source of the campaign.
69
+ # +leads+:: Required. An array of Lead objects or lead keys. If
70
+ # both +leads+ and +lead+ are provided, they will be
71
+ # merged.
72
+ # +lead+:: An alias for +leads+.
73
+ # +campaign_id+:: The campaign ID to request for the +lead+ or +leads+.
74
+ # Required if +campaign_name+ or +program_name+ are not
75
+ # provided.
76
+ # +campaign_name+:: The campaign name to request for the +lead+ or
77
+ # +leads+. Required if +campaign_id+ or +program_name+
78
+ # are not provided.
79
+ # +program_name+:: The program name to request for the +lead+ or
80
+ # +leads+. Required if +campaign_id+ or +campaign_name+
81
+ # are not provided, or if +program_tokens+ are
82
+ # provided.
83
+ # +program_tokens+:: An array of program tokens in the form:
84
+ # <tt>{ attrib: { name: name, value: value } }</tt>
85
+ # This will be made easier to manage in the future.
86
+ #
87
+ # If possible, prefer #request_marketo and #request_sales.
88
+ #
89
+ # :call-seq:
90
+ # request(options)
91
+ def request(options = {})
92
+ source = options.fetch(:source) { :MKTOWS }
93
+ leads = MarketoAPI.array(options.delete(:leads)) +
94
+ MarketoAPI.array(options.delete(:lead))
95
+ if leads.empty?
96
+ raise ArgumentError, ':lead or :leads must be provided'
97
+ end
98
+
99
+ valid_id = options.has_key?(:campaign_id) ||
100
+ options.has_key?(:campaign_name) || options.has_key?(:program_name)
101
+ unless valid_id
102
+ raise ArgumentError,
103
+ ':campaign_id, :campaign_name, or :program_name must be provided'
104
+ end
105
+
106
+ if options.has_key?(:campaign_id) && options.has_key?(:campaign_name)
107
+ raise ArgumentError,
108
+ ':campaign_id and :campaign_name are mutually exclusive'
109
+ end
110
+
111
+ if (tokens = options.delete(:program_tokens)) && !tokens.empty?
112
+ if !options[:program_name]
113
+ raise KeyError,
114
+ ':program_name must be provided when using :program_tokens'
115
+ end
116
+ end
117
+
118
+ call(
119
+ :request_campaign,
120
+ options.merge(
121
+ source: resolve_source(source),
122
+ lead_list: transform_param_list(:get, leads),
123
+ program_token_list: tokens
124
+ ).delete_if(&MarketoAPI::MINIMIZE_HASH)
125
+ )
126
+ end
127
+
128
+ ##
129
+ # :method: request_marketo
130
+ #
131
+ # Implements +getCampaignsForSource+ for the +marketo+ source; a
132
+ # specialization of #request.
133
+ #
134
+ # :call-seq:
135
+ # request_marketo(options)
136
+
137
+ ##
138
+ # :method: request_sales
139
+ #
140
+ # Implements +getCampaignsForSource+ for the +sales+ source; a
141
+ # specialization of #request.
142
+ #
143
+ # :call-seq:
144
+ # request_sales(options)
145
+
146
+ # Implements
147
+ # {+scheduleCampaign+}[http://developers.marketo.com/documentation/soap/schedulecampaign/].
148
+ #
149
+ # === Optional Parameters
150
+ #
151
+ # +run_at+:: The time to run the scheduled campaign.
152
+ # +program_tokens+:: An array of program tokens in the form:
153
+ # <tt>{ attrib: { name: name, value: value } }</tt>
154
+ # This will be made easier to manage in the future.
155
+ #
156
+ # +source+ must be +marketo+ or +sales+ or the equivalent enumerated
157
+ # values from the SOAP environment (+MKTOWS+ or +SALES+).
158
+ #
159
+ # :call-seq:
160
+ # schedule(program_name, campaign_name, options = {})
161
+ def schedule(program_name, campaign_name, options = {})
162
+ call(
163
+ :schedule_campaign,
164
+ {
165
+ program_name: program_name,
166
+ campaign_name: campaign_name,
167
+ campaign_run_at: options[:run_at],
168
+ program_token_list: options[:program_tokens]
169
+ }.delete_if(&MarketoAPI::MINIMIZE_HASH)
170
+ )
171
+ end
172
+
173
+ SOURCES.each_pair { |source, enum|
174
+ define_method(:"for_#{source}") do |name = nil, exact_name = nil|
175
+ for_source(enum, name, exact_name)
176
+ end
177
+
178
+ define_method(:"request_#{source}") do |options = {}|
179
+ request(options.merge(source: enum))
180
+ end
181
+ }
182
+
183
+ private
184
+ def resolve_source(source)
185
+ source = source.to_sym
186
+ res = if ENUMS.include? source
187
+ source
188
+ else
189
+ SOURCES[source]
190
+ end
191
+ raise ArgumentError, "Invalid source #{source}" unless res
192
+ res
193
+ end
194
+ end