salesforce_record 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|
+
[](https://travis-ci.org/mru2/salesforce_record) [](https://coveralls.io/r/mru2/salesforce_record) [](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:
|