amorail 0.1.6 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 151952934c801a5cce9b699869f1e46bd88f4e6a
4
- data.tar.gz: 9ed39010c5f080bd68c07d35fc3434edba549b4d
3
+ metadata.gz: 7d135728d3ff91d041ff0114f7674f548758ede9
4
+ data.tar.gz: 66c9aef842b6989ceb4eca793358e9d6c61140ca
5
5
  SHA512:
6
- metadata.gz: a11232b9fbc2f0b93f87d90e14c8ac068dff7281e732727156229708e3cb8bb0f1406840922ad203f41cbd451bd0d926e75d46c1c37a3f2893ff20a65d100069
7
- data.tar.gz: 0eba066877b078d2676e0c9896b5c36a6a9451cf5894c4cabe0b83377c2d65b528970e8bc5bfc2cdd7e2185d789136fb8db8ce0faa2034181b624bd03997dce8
6
+ metadata.gz: 9bb9ea6019c46ce4ec6778abbc45d6d1c1c7dee9fe99177ab9a7753b810d7a6495c9f813eab700309b17e9f3e85bf7af359d4b1e798c09d5355244a3aadb2377
7
+ data.tar.gz: 2671b2d09412cda7bba66d90961a474fad00848a39e004cf22f6ecb76821e98412966151158f855caee92631ed8dd31ff56217ac4e003d9836cdb7649a91f9f7
data/README.md CHANGED
@@ -22,7 +22,143 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- TODO: Write usage instructions here
25
+ With Amorail you can manipulate the following AmoCRM entities: Companies, Contacts, Leads and Tasks.
26
+ We're triying to build simple AR-like interface.
27
+
28
+ ### Auth configuration
29
+
30
+ Amorail uses [anyway_config](https://github.com/palkan/anyway_config) for configuration, so you
31
+ can provide configuration parameters through env vars, seperate config file (`config/amorail.yml`) or `secrets.yml`.
32
+
33
+ Required params: **usermail**, **api_key** and **api_endpoint**.
34
+
35
+ Example:
36
+
37
+ ```
38
+ # config/secrets.yml
39
+ development:
40
+ ...
41
+ amorail:
42
+ usermail: 'amorail@test.com'
43
+ api_key: '75742b166417fe32ae132282ce178cf6'
44
+ api_endpoint: 'https://test.amocrm.ru'
45
+ ```
46
+
47
+ ### Running from console
48
+
49
+ You can try amorail in action from console ([PRY](https://github.com/pry/pry) is required to be installed):
50
+
51
+ ```shell
52
+ # amorail gem directory
53
+ AMORAIL_USERMAIL=my_mail@test.com AMORAIL_API_KEY=my_key AMORAIL_API_ENDPOINT=my@amo.com bundle exec rake console
54
+ pry> Amorail.properties
55
+ # ... prints properties (custom_fields) data
56
+ pry> Amorail::Contact.find_by_query("test_contact")
57
+ # ... returns array of contacts which satisfy the query
58
+ ```
59
+
60
+ ### Create new objects
61
+
62
+ Create Leads
63
+
64
+ ```ruby
65
+ lead = Amorail::Lead.new(
66
+ name: "Example Lead",
67
+ tags: "IT, Sales",
68
+ price: 100,
69
+ status_id: Amorail.properties.leads.statuses[
70
+ Rails.application.secrets.amoparams['lead_status']
71
+ ].id
72
+ )
73
+
74
+ lead.save!
75
+ ```
76
+
77
+ Create Company
78
+
79
+ ```ruby
80
+ company = Amorail::Company.new(
81
+ name: "My company",
82
+ phone: "222-111",
83
+ email: "human@example.com"
84
+ )
85
+ company.linked_leads_id << lead.id
86
+ company.save!
87
+ ```
88
+
89
+ Create Contact
90
+
91
+ ```ruby
92
+ contact = Amorail::Contact.new(
93
+ name: "Ivan Ivanov",
94
+ linked_company_id: company.id,
95
+ phone: "111-222",
96
+ email: "ivan@example.com"
97
+ )
98
+
99
+ contact.linked_leads_id << lead.id
100
+ contact.save!
101
+ ```
102
+
103
+ Create Task
104
+
105
+ ```ruby
106
+ task = Amorail::Task.new(
107
+ text: "Example task",
108
+ lead: true,
109
+ complete_till: Time.zone.today.end_of_day,
110
+ task_type: Amorail.properties.tasks[Rails.application.secrets.amoparams['task_code']].id
111
+ )
112
+
113
+ # set up lead id
114
+ task.element_id = lead.id
115
+ # and save it
116
+ task.save!
117
+ ```
118
+
119
+ You can find any object by id:
120
+
121
+ ```ruby
122
+ Amorail::Company.find(company_id)
123
+ ```
124
+
125
+ Or using query:
126
+
127
+ ```ruby
128
+ Amorail::Company.find_by_query("vip")
129
+ ```
130
+
131
+ Also you can update objects, e.g:
132
+
133
+ ```ruby
134
+ company = Amorail::Company.find(company_id)
135
+ contact = Amorail::Contact.find(contact_id)
136
+
137
+ # like this
138
+ contact.linked_company_id = company.id
139
+ contact.save!
140
+
141
+ # or
142
+
143
+ contact.update(linked_company_id: company.id)
144
+ ```
145
+
146
+
147
+ ### Properties Configuration
148
+
149
+ AmoCRM is using "custom_fields" architecture,
150
+ to get all information for your account, you can
151
+ find properties and set up configuration manually in config/secrets.yml.
152
+
153
+ Note: response example in official documentation:
154
+ https://developers.amocrm.ru/rest_api/accounts_current.php
155
+
156
+ 1) Get list of properties for your account
157
+
158
+ ```
159
+ rake amorail:check
160
+ ```
161
+ Rake task will returns information about properties.
26
162
 
27
163
  ## Contributing
28
164
 
data/Rakefile CHANGED
@@ -6,3 +6,6 @@ RSpec::Core::RakeTask.new(:spec)
6
6
 
7
7
  task :default => :spec
8
8
 
9
+ task :console do
10
+ sh 'pry -r ./lib/amorail.rb'
11
+ end
@@ -71,7 +71,7 @@ module Amorail
71
71
  when 403
72
72
  fail ::Amorail::AmoForbiddenError
73
73
  when 404
74
- fail ::Amorail::AmoNotFoudError
74
+ fail ::Amorail::AmoNotFoundError
75
75
  when 500
76
76
  fail ::Amorail::AmoInternalError
77
77
  when 502
@@ -12,6 +12,11 @@ module Amorail
12
12
  class << self
13
13
  attr_reader :amo_name, :amo_response_name
14
14
 
15
+ # copy Amo names
16
+ def inherited(subclass)
17
+ subclass.amo_names amo_name, amo_response_name
18
+ end
19
+
15
20
  def amo_names(name, response_name = nil)
16
21
  @amo_name = @amo_response_name = name
17
22
  @amo_response_name = response_name unless response_name.nil?
@@ -34,17 +39,20 @@ module Amorail
34
39
  end
35
40
 
36
41
  def properties
37
- @properties ||= {}
42
+ @properties ||=
43
+ superclass.respond_to?(:properties) ? superclass.properties.dup : {}
38
44
  end
39
- end
40
45
 
41
- amo_names 'entity'
46
+ def remote_url(action)
47
+ File.join(Amorail.config.api_path, amo_name, action)
48
+ end
49
+ end
42
50
 
43
51
  amo_field :id, :request_id, :responsible_user_id,
44
52
  date_create: :timestamp, last_modified: :timestamp
45
53
 
46
54
  delegate :client, :properties, to: Amorail
47
- delegate :amo_name, to: :class
55
+ delegate :amo_name, :remote_url, to: :class
48
56
 
49
57
  def initialize(attributes = {})
50
58
  super(attributes)
@@ -75,16 +83,14 @@ module Amorail
75
83
  def merge_custom_fields(fields)
76
84
  return if fields.nil?
77
85
  fields.each do |f|
78
- fname = "#{f.fetch('code').downcase}="
86
+ fname = f['code'] || f['name']
87
+ next if fname.nil?
88
+ fname = "#{fname.downcase}="
79
89
  fval = f.fetch('values').first.fetch('value')
80
90
  send(fname, fval) if respond_to?(fname)
81
91
  end
82
92
  end
83
93
 
84
- def remote_url(action)
85
- File.join(Amorail.config.api_path, self.class.amo_name, action)
86
- end
87
-
88
94
  # call safe method <safe_request>. safe_request call authorize
89
95
  # if current session undefined or expires.
90
96
  def push(method)
@@ -1,15 +1,32 @@
1
1
  module Amorail # :nodoc: all
2
2
  class Entity
3
3
  class << self
4
+ # Find AMO entity by id
4
5
  def find(id)
5
6
  new.load_record(id)
6
7
  end
7
8
 
9
+ # Find AMO entity by id
10
+ # and raise RecordNotFound if nothing was found
8
11
  def find!(id)
9
12
  rec = find(id)
10
13
  fail RecordNotFound unless rec
11
14
  rec
12
15
  end
16
+
17
+ # Find AMO entities by query
18
+ # Returns array of matching entities.
19
+ def find_by_query(q)
20
+ response = Amorail.client.safe_request(
21
+ :get,
22
+ remote_url('list'),
23
+ query: q
24
+ )
25
+ return [] unless response.status == 200
26
+
27
+ (response.body['response'][amo_response_name] || [])
28
+ .map { |info| new.reload_model(info) }
29
+ end
13
30
  end
14
31
 
15
32
  def load_record(id)
@@ -13,7 +13,7 @@ module Amorail
13
13
 
14
14
  class AmoForbiddenError < APIError; end
15
15
 
16
- class AmoNotFoudError < APIError; end
16
+ class AmoNotFoundError < APIError; end
17
17
 
18
18
  class AmoInternalError < APIError; end
19
19
 
@@ -19,8 +19,10 @@ module Amorail
19
19
 
20
20
  def parse(data)
21
21
  hash = {}
22
- data['custom_fields'][source_name].each do |contact|
23
- hash[contact['code'].downcase] = PropertyItem.new(contact)
22
+ data['custom_fields'].fetch(source_name, []).each do |contact|
23
+ identifier = contact['code'].presence || contact['name'].presence
24
+ next if identifier.nil?
25
+ hash[identifier.downcase] = PropertyItem.new(contact)
24
26
  end
25
27
  new hash
26
28
  end
@@ -87,23 +89,33 @@ module Amorail
87
89
  self.source_name = 'companies'
88
90
  end
89
91
 
90
- class Lead < StatusItem
91
- def self.parse(data)
92
- hash = {}
93
- data['leads_statuses'].each do |prop|
94
- hash[prop['name']] = PropertyItem.new(prop)
92
+ class Lead < PropertyItem
93
+ self.source_name = 'leads'
94
+
95
+ attr_accessor :statuses
96
+
97
+ class << self
98
+ def parse(data)
99
+ obj = super
100
+ hash = {}
101
+ data.fetch('leads_statuses', []).each do |prop|
102
+ hash[prop['name']] = PropertyItem.new(prop)
103
+ end
104
+ obj.statuses = hash
105
+ obj
95
106
  end
96
- new hash
97
107
  end
98
108
  end
99
109
 
100
110
  class Task < PropertyItem
101
111
  def self.parse(data)
102
112
  hash = {}
103
- data['task_types'].each do |tt|
113
+ data.fetch('task_types', []).each do |tt|
104
114
  prop_item = PropertyItem.new(tt)
105
- hash[tt['code'].downcase] = prop_item
106
- hash[tt['code']] = prop_item
115
+ identifier = tt['code'].presence || tt['name'].presence
116
+ next if identifier.nil?
117
+ hash[identifier.downcase] = prop_item
118
+ hash[identifier] = prop_item
107
119
  end
108
120
  new hash
109
121
  end
@@ -1,4 +1,4 @@
1
1
  # Amorail version
2
2
  module Amorail
3
- VERSION = "0.1.6"
3
+ VERSION = "0.1.8"
4
4
  end
@@ -91,6 +91,28 @@ describe Amorail::Contact do
91
91
  end
92
92
  end
93
93
 
94
+ describe ".find_by_query" do
95
+ before { contacts_find_query_stub(Amorail.config.api_endpoint, 'foo') }
96
+ before { contacts_find_query_stub(Amorail.config.api_endpoint, 'faa', nil) }
97
+
98
+ it "loads entities" do
99
+ res = described_class.find_by_query('foo')
100
+ expect(res.size).to eq 2
101
+ expect(res.first.id).to eq 101
102
+ expect(res.last.id).to eq 102
103
+ expect(res.first.company_name).to eq "Foo Inc."
104
+ expect(res.last.email).to eq "foo2@tb.com"
105
+ expect(res.first.phone).to eq "1111 111 111"
106
+ expect(res.first.params[:id]).to eq 101
107
+ end
108
+
109
+ it "returns empty array" do
110
+ res = described_class.find_by_query('faa')
111
+ expect(res).to be_a(Array)
112
+ expect(res).to be_empty
113
+ end
114
+ end
115
+
94
116
  describe "#save" do
95
117
  before { contact_create_stub(Amorail.config.api_endpoint) }
96
118
 
@@ -114,13 +136,14 @@ describe Amorail::Contact do
114
136
 
115
137
  it "raise error if id is blank?" do
116
138
  obj = described_class.new
117
- expect { obj.update!(name: 'Igor') }.to raise_error
139
+ expect { obj.update!(name: 'Igor') }
140
+ .to raise_error(Amorail::Entity::NotPersisted)
118
141
  end
119
142
 
120
143
  it "raise error" do
121
144
  obj = described_class.new
122
145
  expect { obj.update!(id: 101, name: "Igor") }
123
- .to(raise_error)
146
+ .to(raise_error(Amorail::Entity::NotPersisted))
124
147
  end
125
148
  end
126
149
  end
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Amorail::Entity do
3
+ describe MyEntity do
4
4
  before { mock_api }
5
5
 
6
6
  let(:entity) { described_class.new }
@@ -139,8 +139,30 @@
139
139
  "3392112": "MSN",
140
140
  "3392114": "OTHER"
141
141
  }
142
+ },
143
+ {
144
+ "id": "116302",
145
+ "name": "teachbase_id",
146
+ "multiple": "N",
147
+ "type_id": "8"
142
148
  }
143
149
  ],
150
+ "leads": [
151
+ {
152
+ "id": "484604",
153
+ "name": "textfield",
154
+ "code": null,
155
+ "multiple": "N",
156
+ "type_id": "1"
157
+ },
158
+ {
159
+ "id": "484606",
160
+ "name": "Flag",
161
+ "code": null,
162
+ "multiple": "N",
163
+ "type_id": "3"
164
+ }
165
+ ],
144
166
  "companies": [
145
167
  {
146
168
  "id": "1460589",
@@ -0,0 +1,59 @@
1
+ {
2
+ "response": {
3
+ "contacts": [
4
+ {
5
+ "id": 101,
6
+ "name": "Foo bar",
7
+ "account_id": "8195968",
8
+ "last_modified": 1423139130,
9
+ "company_name": "Foo Inc.",
10
+ "custom_fields":
11
+ [
12
+ {
13
+ "id": "1460591",
14
+ "name": "Email",
15
+ "code": "EMAIL",
16
+ "values": [
17
+ {
18
+ "value": "foo@tb.com",
19
+ "enum": "3392098"
20
+ }
21
+ ]
22
+ },
23
+ {
24
+ "id": "1460589",
25
+ "name": "Телефон",
26
+ "code": "PHONE",
27
+ "values": [
28
+ {
29
+ "value": "1111 111 111",
30
+ "enum": "3392086"
31
+ }
32
+ ]
33
+ }
34
+ ]
35
+ },
36
+ {
37
+ "id": 102,
38
+ "name": "Foo bar 2",
39
+ "account_id": "8195968",
40
+ "last_modified": 1423139150,
41
+ "company_name": "Foo Inc.",
42
+ "custom_fields":
43
+ [
44
+ {
45
+ "id": "1460591",
46
+ "name": "Email",
47
+ "code": "EMAIL",
48
+ "values": [
49
+ {
50
+ "value": "foo2@tb.com",
51
+ "enum": "3392098"
52
+ }
53
+ ]
54
+ }
55
+ ]
56
+ }
57
+ ]
58
+ }
59
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "response": {
3
+ "contacts": [
4
+ {
5
+ "id": 11,
6
+ "name": "Foo bar",
7
+ "account_id": "8195968",
8
+ "last_modified": 1423139130,
9
+ "company_name": "Foo Inc.",
10
+ "custom_fields":
11
+ [
12
+ {
13
+ "id": "1460591",
14
+ "name": "Email",
15
+ "code": "EMAIL",
16
+ "values": [
17
+ {
18
+ "value": "foo@tb.com",
19
+ "enum": "3392098"
20
+ }
21
+ ]
22
+ },
23
+ {
24
+ "id": "1460589",
25
+ "name": "Телефон",
26
+ "code": "PHONE",
27
+ "values": [
28
+ {
29
+ "value": "1111 111 111",
30
+ "enum": "3392086"
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ "id": "116302",
36
+ "name": "teachbase_id",
37
+ "values": [
38
+ {
39
+ "value": 1123,
40
+ "enum": "3392090"
41
+ }
42
+ ]
43
+ }
44
+ ]
45
+ }
46
+ ]
47
+ }
48
+ }
@@ -1,3 +1,4 @@
1
+ # rubocop: disable Metrics/ModuleLength
1
2
  module AmoWebMock
2
3
  def mock_api
3
4
  authorize_stub(
@@ -85,6 +86,42 @@ module AmoWebMock
85
86
  end
86
87
  end
87
88
 
89
+ def my_contact_find_stub(endpoint, id, success = true)
90
+ if success
91
+ stub_request(
92
+ :get,
93
+ "#{endpoint}/private/api/v2/json/contacts/list?id=#{id}")
94
+ .to_return(
95
+ body: File.read('./spec/fixtures/my_contact_find.json'),
96
+ headers: { 'Content-Type' => 'application/json' },
97
+ status: 200
98
+ )
99
+ else
100
+ stub_request(
101
+ :get,
102
+ "#{endpoint}/private/api/v2/json/contacts/list?id=#{id}")
103
+ .to_return(body: nil, status: 204)
104
+ end
105
+ end
106
+
107
+ def contacts_find_query_stub(endpoint, query, success = true)
108
+ if success
109
+ stub_request(
110
+ :get,
111
+ "#{endpoint}/private/api/v2/json/contacts/list?query=#{query}")
112
+ .to_return(
113
+ body: File.read('./spec/fixtures/contact_find_query.json'),
114
+ headers: { 'Content-Type' => 'application/json' },
115
+ status: 200
116
+ )
117
+ else
118
+ stub_request(
119
+ :get,
120
+ "#{endpoint}/private/api/v2/json/contacts/list?query=#{query}")
121
+ .to_return(status: 204)
122
+ end
123
+ end
124
+
88
125
  def company_create_stub(endpoint)
89
126
  stub_request(:post, endpoint + '/private/api/v2/json/company/set')
90
127
  .to_return(
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ describe MyContact do
4
+ before { mock_api }
5
+
6
+ describe ".properties" do
7
+ subject { described_class.properties }
8
+
9
+ specify do
10
+ is_expected.to include(:email, :phone, :teachbase_id)
11
+ end
12
+ end
13
+
14
+ describe "#params" do
15
+ let(:company) do
16
+ described_class.new(
17
+ name: 'Test inc',
18
+ phone: '12345678',
19
+ email: 'test@mala.ru',
20
+ teachbase_id: 123
21
+ )
22
+ end
23
+
24
+ subject { company.params }
25
+
26
+ specify { is_expected.to include(:last_modified) }
27
+ specify { is_expected.to include(name: 'Test inc') }
28
+
29
+ it "contains custom property" do
30
+ prop = subject[:custom_fields].detect { |p| p[:id] == "116302" }
31
+ expect(prop).not_to be_nil
32
+ expect(prop[:values].first[:value]).to eq 123
33
+ end
34
+ end
35
+
36
+ describe ".find" do
37
+ before { my_contact_find_stub(Amorail.config.api_endpoint, 11) }
38
+
39
+ it "loads entity" do
40
+ obj = described_class.find(11)
41
+ expect(obj.id).to eq 11
42
+ expect(obj.company_name).to eq "Foo Inc."
43
+ expect(obj.email).to eq "foo@tb.com"
44
+ expect(obj.teachbase_id).to eq 1123
45
+ expect(obj.params[:id]).to eq 11
46
+ end
47
+ end
48
+ end
@@ -28,9 +28,12 @@ describe Amorail::Property do
28
28
  expect(prop.contacts.position.id).to eq "1460587"
29
29
  expect(prop.contacts.phone.id).to eq "1460589"
30
30
  expect(prop.contacts.email.id).to eq "1460591"
31
+ expect(prop.contacts.teachbase_id.id).to eq "116302"
31
32
  end
32
33
 
33
34
  it "should parse leads hash" do
35
+ expect(prop.leads.textfield.id).to eq "484604"
36
+ expect(prop.leads.flag.id).to eq "484606"
34
37
  expect(prop.leads.statuses["Первичный контакт"].id).to eq "8195972"
35
38
  expect(prop.leads.statuses["Успешно реализовано"].id).to eq "142"
36
39
  end
@@ -8,7 +8,8 @@ require 'webmock/rspec'
8
8
  require 'shoulda/matchers'
9
9
  require 'helpers/webmock_helpers'
10
10
 
11
- ENV.clear
11
+ # Cleanup Amorail env
12
+ ENV.delete_if { |k, _| k =~ /amorail/i }
12
13
  ENV["AMORAIL_CONF"] = File.expand_path("../fixtures/amorail_test.yml", __FILE__)
13
14
 
14
15
  Dir[File.expand_path("../support/**/*.rb", __FILE__)].each { |f| require f }
@@ -0,0 +1,3 @@
1
+ class MyContact < Amorail::Contact # :nodoc:
2
+ amo_property :teachbase_id
3
+ end
@@ -0,0 +1,4 @@
1
+ # We only need this class to set Amo names for core Entity
2
+ class MyEntity < Amorail::Entity # :nodoc:
3
+ amo_names 'entity'
4
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amorail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - alekseenkoss
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-27 00:00:00.000000000 Z
12
+ date: 2015-06-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -213,13 +213,18 @@ files:
213
213
  - spec/fixtures/amorail_test.yml
214
214
  - spec/fixtures/contact_create.json
215
215
  - spec/fixtures/contact_find.json
216
+ - spec/fixtures/contact_find_query.json
216
217
  - spec/fixtures/contact_update.json
218
+ - spec/fixtures/my_contact_find.json
217
219
  - spec/helpers/webmock_helpers.rb
218
220
  - spec/lead_spec.rb
221
+ - spec/my_contact_spec.rb
219
222
  - spec/property_spec.rb
220
223
  - spec/spec_helper.rb
221
224
  - spec/support/entity_class_example.rb
222
225
  - spec/support/leadable_example.rb
226
+ - spec/support/my_contact.rb
227
+ - spec/support/my_entity.rb
223
228
  - spec/task_spec.rb
224
229
  homepage: ''
225
230
  licenses:
@@ -254,12 +259,17 @@ test_files:
254
259
  - spec/fixtures/amorail_test.yml
255
260
  - spec/fixtures/contact_create.json
256
261
  - spec/fixtures/contact_find.json
262
+ - spec/fixtures/contact_find_query.json
257
263
  - spec/fixtures/contact_update.json
264
+ - spec/fixtures/my_contact_find.json
258
265
  - spec/helpers/webmock_helpers.rb
259
266
  - spec/lead_spec.rb
267
+ - spec/my_contact_spec.rb
260
268
  - spec/property_spec.rb
261
269
  - spec/spec_helper.rb
262
270
  - spec/support/entity_class_example.rb
263
271
  - spec/support/leadable_example.rb
272
+ - spec/support/my_contact.rb
273
+ - spec/support/my_entity.rb
264
274
  - spec/task_spec.rb
265
275
  has_rdoc: