salesforce_record 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +69 -0
- data/lib/salesforce_record.rb +34 -0
- data/lib/salesforce_record/attributes.rb +152 -0
- data/lib/salesforce_record/base.rb +36 -0
- data/lib/salesforce_record/fields.rb +80 -0
- data/lib/salesforce_record/finder.rb +101 -0
- data/lib/salesforce_record/persistence.rb +79 -0
- data/lib/salesforce_record/version.rb +3 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6ad16d2a059b16aff6a15262ab0552d83d3d12f9
|
4
|
+
data.tar.gz: 48123ec4187661eae7f4cd93c20bebbd9e5c4ead
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: feea79ba0c8a43da14fa76a52c2cfc253357be6ab6d480f5b3373cea59fa7f99a4f24979e244687a693e1435cbdad23a31cbadf087929f53a182e2015f29677b
|
7
|
+
data.tar.gz: 577b8ab8cec74c6834298afdb5173443d3b8c3d4f9f03dda8f1d44ca58623eb18163bba24ca5e52a9f5711777aa82ff415b2d8360f2caf990e67bc3d6884d998
|
data/README.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# SalesforceRecord
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/mru2/salesforce_record.png?branch=master)](https://travis-ci.org/mru2/salesforce_record) [![Coverage Status](https://coveralls.io/repos/mru2/salesforce_record/badge.png)](https://coveralls.io/r/mru2/salesforce_record) [![Code Climate](https://codeclimate.com/github/mru2/salesforce_record.png)](https://codeclimate.com/github/mru2/salesforce_record)
|
4
|
+
|
5
|
+
ActiveRecord-like mixin for querying, fetching and updating Salesforce models
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'salesforce_record'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install salesforce_record
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
```
|
24
|
+
require 'salesforce_adapter'
|
25
|
+
require 'salesforce_record'
|
26
|
+
|
27
|
+
$salesforce = SalesforceAdapter::Base.new(
|
28
|
+
:url => 'https://test.salesforce.com/services/Soap/u/16.0',
|
29
|
+
:login => 'your_salesforce_login',
|
30
|
+
:password => 'your_salesforce_password'
|
31
|
+
)
|
32
|
+
|
33
|
+
class MyLeadModel
|
34
|
+
include SalesforceRecord
|
35
|
+
|
36
|
+
is_salesforce_model :Lead
|
37
|
+
sf_adapter $salesforce
|
38
|
+
sf_attributes :Company, :FirstName, :LastName
|
39
|
+
end
|
40
|
+
|
41
|
+
# Finders
|
42
|
+
> lead = MyLeadModel.find('00Qg000000ORDER66')
|
43
|
+
=> #<MyLeadModel:0x007fe47983b700 @Id="00Qg000000ORDER66", @Company="JEDI inc", @FirstName="Mace", @LastName="Windu">
|
44
|
+
|
45
|
+
# Attribute getters
|
46
|
+
> lead.Company
|
47
|
+
=> "JEDI inc"
|
48
|
+
|
49
|
+
# Remote setters
|
50
|
+
> lead.update_fields(:Company => 'One-arm support group')
|
51
|
+
=> true
|
52
|
+
|
53
|
+
# Record creation
|
54
|
+
> new_lead = MyLeadModel.create(:LastName => 'Binks', :FirstName => 'Jar-Jar', :Company => 'Lobby for a new Autocracy')
|
55
|
+
=> #<MyLeadModel:0x007fe4798e1970 @Id="00Qg0000002DUMBASS", @Company="Unwilling Dictatorship Lobby", @FirstName="Jar-Jar", @LastName="Binks">
|
56
|
+
|
57
|
+
# Queries
|
58
|
+
> results = MyLeadModel.where(:LastName => 'Windu')
|
59
|
+
=> [#<MyLeadModel:0x007fe47991bee0 @Id="00Qg000000ORDER66", @Company="One-arm support group", @FirstName="Mace", @LastName="Windu">]
|
60
|
+
```
|
61
|
+
|
62
|
+
|
63
|
+
## Contributing
|
64
|
+
|
65
|
+
1. Fork it ( http://github.com/<my-github-username>/salesforce_record/fork )
|
66
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
67
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
68
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
69
|
+
5. Create new Pull Request
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Module allowing a class to wrap a salesforce object
|
2
|
+
# Define accessors and finder methods
|
3
|
+
|
4
|
+
# Usage :
|
5
|
+
# class Lead
|
6
|
+
# is_salesforce_model :Lead
|
7
|
+
# include SalesforceRecord
|
8
|
+
# sf_adapter salesforce_adapter
|
9
|
+
# sf_attributes :ConvertedAccountId, :Street
|
10
|
+
# sf_attribute :owner_email, :from => 'Owner.Email'
|
11
|
+
# sf_attribute :Date_saisie_CB__c, :type => :date
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# lead = Lead.find('my_lead_id', rforce_salesforce_adapter)
|
15
|
+
# lead.owner_email # => "my@email.tld"
|
16
|
+
|
17
|
+
require 'salesforce_record/version'
|
18
|
+
|
19
|
+
require 'salesforce_record/base'
|
20
|
+
require 'salesforce_record/attributes'
|
21
|
+
require 'salesforce_record/finder'
|
22
|
+
require 'salesforce_record/persistence'
|
23
|
+
|
24
|
+
module SalesforceRecord
|
25
|
+
|
26
|
+
def self.included(base)
|
27
|
+
# Include dependencies
|
28
|
+
base.send :include, SalesforceRecord::Base
|
29
|
+
base.send :include, SalesforceRecord::Attributes
|
30
|
+
base.send :include, SalesforceRecord::Finder
|
31
|
+
base.send :include, SalesforceRecord::Persistence
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# Attributes handling
|
2
|
+
# defines #new and #attributes
|
3
|
+
# also class methods for parsing / encoding attributes hash for salesforce
|
4
|
+
|
5
|
+
require 'salesforce_record/fields'
|
6
|
+
|
7
|
+
module SalesforceRecord
|
8
|
+
module Attributes
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.send(:extend, ClassMethods)
|
12
|
+
|
13
|
+
base.instance_eval do
|
14
|
+
# Store the attributes and aliases at the class level
|
15
|
+
@salesforce_fields = {} # name => field instance
|
16
|
+
|
17
|
+
# The base attributes
|
18
|
+
sf_attribute :Id, :type => :id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
|
25
|
+
# The salesforce fields and options
|
26
|
+
def salesforce_fields ; @salesforce_fields ; end
|
27
|
+
|
28
|
+
# The attributes for this model
|
29
|
+
def salesforce_attributes ; @salesforce_fields.keys ; end
|
30
|
+
|
31
|
+
# Add salesforce attributes to the model
|
32
|
+
def sf_attributes(*attrs)
|
33
|
+
attrs.each do |attr|
|
34
|
+
sf_attribute attr
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add a salesforce attribute to the model
|
39
|
+
# Possible options :
|
40
|
+
# :from => the remote key to fetch to populate the field
|
41
|
+
# :type => one of :date, :float, :integer, :boolean, :id
|
42
|
+
def sf_attribute(attribute, opts={})
|
43
|
+
|
44
|
+
case opts[:type]
|
45
|
+
when :date
|
46
|
+
@salesforce_fields[attribute] = Fields::DateField.new(attribute, opts)
|
47
|
+
when :float
|
48
|
+
@salesforce_fields[attribute] = Fields::FloatField.new(attribute, opts)
|
49
|
+
when :integer
|
50
|
+
@salesforce_fields[attribute] = Fields::IntegerField.new(attribute, opts)
|
51
|
+
else
|
52
|
+
@salesforce_fields[attribute] = Fields::BaseField.new(attribute, opts)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Set its accessor
|
56
|
+
attr_reader attribute
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# Create an imported record from salesforce
|
61
|
+
def from_salesforce(fields)
|
62
|
+
new parse_salesforce_fields(fields)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Parse fields coming from salesforce
|
66
|
+
def parse_salesforce_fields(sf_fields)
|
67
|
+
{}.tap do |parsed_fields|
|
68
|
+
sf_fields.each do |name, value|
|
69
|
+
parsed_field = parse_salesforce_field(name, value) unless value.nil?
|
70
|
+
parsed_fields.merge! parsed_field if !parsed_field.nil?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Encode fields for salesforce
|
76
|
+
def encode_salesforce_fields(fields)
|
77
|
+
{}.tap do |encoded_fields|
|
78
|
+
fields.each do |name, value|
|
79
|
+
encoded_field = encode_salesforce_field(name, value)
|
80
|
+
encoded_fields.merge! encoded_field if !encoded_field.nil?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Parse a field coming from salesforce (type)
|
86
|
+
def parse_salesforce_field(name, value)
|
87
|
+
# If existing, parse it depending on type
|
88
|
+
if (field = get_field name)
|
89
|
+
{ field.local_name => field.parse(value) }
|
90
|
+
|
91
|
+
# Else, try to find if it is an alias
|
92
|
+
else
|
93
|
+
find_matching_alias(name => value)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Encode a field from salesforce
|
98
|
+
def encode_salesforce_field(name, value)
|
99
|
+
# If existing, encode it depending on type and alias
|
100
|
+
if (field = get_field name) && (!field.alias?)
|
101
|
+
{ field.remote_name => field.encode(value) }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def get_field(name)
|
106
|
+
self.salesforce_fields[name]
|
107
|
+
end
|
108
|
+
|
109
|
+
def has_field?(name)
|
110
|
+
!!get_field(name)
|
111
|
+
end
|
112
|
+
|
113
|
+
def field_type(name)
|
114
|
+
has_field?(name) && self.salesforce_fields[name].type
|
115
|
+
end
|
116
|
+
|
117
|
+
def field_remote_name(name)
|
118
|
+
has_field?(name) && self.salesforce_fields[name].remote_name
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
# Tries to find a salesforce alias matching a nested hash. Returns the alias name and corresponding value if found
|
123
|
+
def find_matching_alias(nested_hash)
|
124
|
+
self.salesforce_fields.each do |name, field|
|
125
|
+
if (value = field.is_alias_of(nested_hash))
|
126
|
+
return parse_salesforce_field(name, value)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
return nil
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# Constructor
|
136
|
+
def initialize(attributes = {})
|
137
|
+
# Iterate over the salesforce attributes and sets them
|
138
|
+
attributes.each do |name, value|
|
139
|
+
instance_variable_set :"@#{name}", value
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
# The attributes hash : name => parsed value
|
145
|
+
def attributes
|
146
|
+
Hash[*self.class.salesforce_attributes.map{|attr|[attr, self.send(attr)]}.flatten]
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Base dependencies for the salesforce models
|
2
|
+
# Handles the attribute list, the salesforce adapter, ...
|
3
|
+
|
4
|
+
module SalesforceRecord
|
5
|
+
module Base
|
6
|
+
|
7
|
+
# Bulding the class
|
8
|
+
def self.included(base)
|
9
|
+
base.send(:extend, ClassMethods)
|
10
|
+
|
11
|
+
base.instance_eval do
|
12
|
+
@salesforce_table_name = nil
|
13
|
+
@salesforce_adapter = nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
|
20
|
+
# Defines the salesforce table name
|
21
|
+
def is_salesforce_model(table_name)
|
22
|
+
@salesforce_table_name = table_name
|
23
|
+
end
|
24
|
+
def salesforce_table_name ; @salesforce_table_name ; end
|
25
|
+
|
26
|
+
|
27
|
+
# Defines the salesforce adapter
|
28
|
+
def sf_adapter(adapter)
|
29
|
+
@salesforce_adapter = adapter
|
30
|
+
end
|
31
|
+
def salesforce_adapter ; @salesforce_adapter ; end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# All the possible salesforce fields
|
2
|
+
# Responsible for parsing / encoding the values
|
3
|
+
# Also handle local and remote name, if different
|
4
|
+
|
5
|
+
module SalesforceRecord
|
6
|
+
module Fields
|
7
|
+
|
8
|
+
# The base class for the fields. No values parsing or encoding
|
9
|
+
class BaseField
|
10
|
+
|
11
|
+
attr_reader :local_name
|
12
|
+
|
13
|
+
def initialize(name, opts)
|
14
|
+
@local_name = name
|
15
|
+
@remote_name = opts[:from]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Parse : SF => local
|
19
|
+
def parse(value)
|
20
|
+
value
|
21
|
+
end
|
22
|
+
|
23
|
+
# Encode : local => SF
|
24
|
+
def encode(value)
|
25
|
+
value
|
26
|
+
end
|
27
|
+
|
28
|
+
def remote_name
|
29
|
+
@remote_name || @local_name
|
30
|
+
end
|
31
|
+
|
32
|
+
def alias?
|
33
|
+
!!@remote_name
|
34
|
+
end
|
35
|
+
|
36
|
+
# Check if matching nested hash
|
37
|
+
def is_alias_of(nested_hash)
|
38
|
+
return false unless @remote_name
|
39
|
+
deep_fetch(nested_hash, remote_name.split('.').map(&:to_sym))
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# Helper : fetch deep value from a hash
|
45
|
+
def deep_fetch(hash, keys)
|
46
|
+
keys.inject(hash){|subhash, key| subhash.is_a?(Hash) && subhash[key] }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# A date. YYYY-MM-DD on salesforce
|
52
|
+
class DateField < BaseField
|
53
|
+
def encode(value)
|
54
|
+
value.strftime("%Y-%m-%d")
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse(value)
|
58
|
+
Date.parse(value)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# A float
|
64
|
+
class FloatField < BaseField
|
65
|
+
def parse(value)
|
66
|
+
value.to_f
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# An integer
|
72
|
+
class IntegerField < BaseField
|
73
|
+
def parse(value)
|
74
|
+
value.to_i
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# Finder methods
|
2
|
+
# defines #find and #where
|
3
|
+
|
4
|
+
module SalesforceRecord
|
5
|
+
module Finder
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.send(:extend, ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
# Returns the object matching a salesforce id
|
14
|
+
def find(id)
|
15
|
+
where(:Id => id).first
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
# Returns a list of object matching a specific query
|
20
|
+
def where(query)
|
21
|
+
|
22
|
+
# Build the matching query string
|
23
|
+
query_string = query_string(query)
|
24
|
+
|
25
|
+
# Run the query and get the results (always an array)
|
26
|
+
sf_results = salesforce_adapter.query(query_string)
|
27
|
+
|
28
|
+
# Create new objets with the results and return them
|
29
|
+
sf_results.map{|sf_attributes| from_salesforce(sf_attributes)}
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# Creates an soql query for the resource. The query matchers are the argument
|
35
|
+
def query_string(query)
|
36
|
+
|
37
|
+
# The first letter of the model used
|
38
|
+
# i.e : Lead => l
|
39
|
+
# Used in the query : Select l.Type_de_paiement__c from Lead l where Id='id-goes-here'
|
40
|
+
key =
|
41
|
+
|
42
|
+
# Build the base query : select all the attributes in the model table (except "type" : returned but should not be queried)
|
43
|
+
query_string = "Select "
|
44
|
+
query_string << (salesforce_attributes - [:type]).map{|attribute| remote_attribute_name(attribute)}.join(", ")
|
45
|
+
query_string << " from #{salesforce_table_name} #{salesforce_query_key}"
|
46
|
+
|
47
|
+
# Add the selectors
|
48
|
+
if query.is_a? String
|
49
|
+
soql_selector = query
|
50
|
+
else
|
51
|
+
soql_selector = query.map{|attribute, value| format_where_clause(attribute, value)}.join(' AND ')
|
52
|
+
end
|
53
|
+
|
54
|
+
query_string << " WHERE #{soql_selector}"
|
55
|
+
|
56
|
+
query_string
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# The key used to namespace the salesforce queries : first character of the table name
|
62
|
+
# i.e : Lead => l
|
63
|
+
# Used in : Select l.Type_de_paiement__c from Lead l where Id='id-goes-here'
|
64
|
+
def salesforce_query_key
|
65
|
+
self.salesforce_table_name.to_s[0, 1].downcase
|
66
|
+
end
|
67
|
+
|
68
|
+
# Aliases : the remote name for an attribute
|
69
|
+
def remote_attribute_name(attribute)
|
70
|
+
if (field = self.get_field attribute)
|
71
|
+
name_without_alias = field.remote_name
|
72
|
+
else
|
73
|
+
name_without_alias = attribute
|
74
|
+
end
|
75
|
+
"#{salesforce_query_key}.#{name_without_alias}"
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
# Create the query string for an attribute/value pair
|
81
|
+
# Returns something along the lines of "key.attribute='value'", to be injected in a WHERE clause
|
82
|
+
def format_where_clause(attribute, value)
|
83
|
+
q = "#{remote_attribute_name(attribute)}=" #exact match
|
84
|
+
|
85
|
+
# No escaping boolean values
|
86
|
+
if value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
87
|
+
q << value.to_s
|
88
|
+
elsif value.is_a? Date
|
89
|
+
q << value.strftime("%Y-%m-%d")
|
90
|
+
elsif value.nil?
|
91
|
+
q << "NULL"
|
92
|
+
else
|
93
|
+
q << "'#{value}'"
|
94
|
+
end
|
95
|
+
|
96
|
+
q
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Persisting the model to salesforce
|
2
|
+
# defines #update_fields and #create methods
|
3
|
+
|
4
|
+
require 'salesforce_adapter'
|
5
|
+
|
6
|
+
module SalesforceRecord
|
7
|
+
module Persistence
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.send(:extend, ClassMethods)
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
# Pushes new field values to salesforce and updates them locally
|
15
|
+
def update_fields(fields)
|
16
|
+
|
17
|
+
update_fields = self.class.encode_attributes(fields).merge({
|
18
|
+
:Id => self.Id,
|
19
|
+
:type => self.class.salesforce_table_name.to_s
|
20
|
+
})
|
21
|
+
|
22
|
+
begin
|
23
|
+
self.class.salesforce_adapter.update( self.class.salesforce_table_name, update_fields )
|
24
|
+
saved = true
|
25
|
+
rescue SalesforceAdapter::SalesforceFailedUpdate => e
|
26
|
+
# No check of the error code necessary here
|
27
|
+
saved = false
|
28
|
+
end
|
29
|
+
|
30
|
+
# Update the fields locally if the request passed
|
31
|
+
if saved
|
32
|
+
fields.each do |attribute, value|
|
33
|
+
self.instance_variable_set(:"@#{attribute}", value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
return saved
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
module ClassMethods
|
43
|
+
|
44
|
+
# Tries to create an instance, given a set of attributes
|
45
|
+
def create(attributes)
|
46
|
+
|
47
|
+
fields = encode_attributes(attributes).merge(:type => self.salesforce_table_name.to_s)
|
48
|
+
|
49
|
+
# Tries to create it remotely
|
50
|
+
begin
|
51
|
+
id = self.salesforce_adapter.create( self.salesforce_table_name, fields )
|
52
|
+
|
53
|
+
# If successful, return an instance with the given Id
|
54
|
+
return from_salesforce(fields.merge(:Id => id))
|
55
|
+
|
56
|
+
# TODO : have a real handling of failures
|
57
|
+
rescue => e
|
58
|
+
puts e.message
|
59
|
+
return nil
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def encode_attributes(attributes)
|
66
|
+
{}.tap do |encoded_attributes|
|
67
|
+
attributes.each do |name, value|
|
68
|
+
if (field = self.get_field(name))
|
69
|
+
encoded_attributes[name] = field.encode value
|
70
|
+
else
|
71
|
+
encoded_attributes[name] = value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: salesforce_record
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ClicRDV
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: salesforce_adapter
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- david.ruyer@clicrdv.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- README.md
|
63
|
+
- lib/salesforce_record.rb
|
64
|
+
- lib/salesforce_record/attributes.rb
|
65
|
+
- lib/salesforce_record/base.rb
|
66
|
+
- lib/salesforce_record/fields.rb
|
67
|
+
- lib/salesforce_record/finder.rb
|
68
|
+
- lib/salesforce_record/persistence.rb
|
69
|
+
- lib/salesforce_record/version.rb
|
70
|
+
homepage: ''
|
71
|
+
licenses:
|
72
|
+
- MIT
|
73
|
+
metadata: {}
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 2.2.1
|
91
|
+
signing_key:
|
92
|
+
specification_version: 4
|
93
|
+
summary: ActiveRecord-like mixin for querying, fetching and updating Salesforce models
|
94
|
+
test_files: []
|
95
|
+
has_rdoc:
|