levene 0.0.1

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.
data/Manifest.txt ADDED
@@ -0,0 +1,18 @@
1
+ Manifest.txt
2
+ README.markdown
3
+ Rakefile
4
+ levene.gemspec
5
+ lib/levene.rb
6
+ lib/levene/version.rb
7
+ lib/levene/connection.rb
8
+ lib/levene/models/account.rb
9
+ lib/levene/models/base.rb
10
+ lib/levene/models/campaign.rb
11
+ lib/levene/models/campaign_member.rb
12
+ lib/levene/models/contact.rb
13
+ lib/levene/models/lead.rb
14
+ lib/levene/models/opportunity.rb
15
+ lib/levene/extensions/binding.rb
16
+ test/helper.rb
17
+ test/test_login.rb
18
+ test/test_lead_model.rb
data/README.markdown ADDED
@@ -0,0 +1,46 @@
1
+ # Levene
2
+
3
+ * https://github.com/robrasmussen/levene
4
+
5
+
6
+ ## DESCRIPTION
7
+
8
+ A light wrapper around RForce to make working with Salesforce a little
9
+ easier.
10
+
11
+ ## USAGE
12
+
13
+ Levene allows you to easily create models that map to their Salesforce
14
+ API counterpart:
15
+
16
+ class Contact < Levene::Models::Base
17
+ end
18
+
19
+ Levene depends on a few environment variables being defined:
20
+
21
+ SALESFORCE_DEV_USER: The Salesforce account you're using
22
+ SALESFORCE_DEV_PASS: Your Salesforce password + security token
23
+
24
+ (If you don't have a Salesforce dev account or an account with API
25
+ access, you'll have to take care of that first.)
26
+
27
+
28
+ Creating a subclass of Levene::Models::Base will cause the fields of the
29
+ relevant Salesforce object to be looked up, and will create accessors
30
+ and ActiveModel validations based on the field definititions.
31
+
32
+ contact = Contact.new
33
+ contact.valid? #=> false
34
+ contact.errors.full_messages #=> ["Last name can't be blank"]
35
+ contact.first_name = "Ricky"
36
+ contact.last_name = "Roma"
37
+ contact.description = "The guy is a closer."
38
+ contact.save #=> true
39
+ contact.id #=> "00AA000006636drIAA"
40
+
41
+
42
+ This is not a replacement for the ActiveRecord connection adapter for
43
+ Salesforce. Levene is mostly for people who need to push data up to
44
+ Salesforce in the background. *It is not thread-safe*.
45
+
46
+
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require "rubygems"
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+
5
+ Hoe.plugins.delete :rubyforge
6
+ Hoe.plugin :minitest #gem install hoe-seattlerb
7
+ Hoe.plugin :gemspec #gem install hoe-gemspec
8
+
9
+ Hoe.spec 'levene' do
10
+ developer('Robert Rasmussen', 'rob.rasmussen@gmail.com')
11
+
12
+ self.readme_file = 'README.markdown'
13
+ self.extra_rdoc_files = FileList['README.markdown']
14
+
15
+ self.extra_deps << [ 'activemodel', '>=3.0.3' ]
16
+ self.extra_deps << [ 'activesupport', '>=3.0.3' ]
17
+ self.extra_deps << [ 'rforce', '~>0.6.0' ]
18
+
19
+ self.extra_dev_deps << [ 'nokogiri', '>=1.4.4' ]
20
+ end
21
+
data/levene.gemspec ADDED
@@ -0,0 +1,50 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{levene}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Robert Rasmussen"]
9
+ s.date = %q{2011-01-20}
10
+ s.description = %q{A light wrapper around RForce to make working with Salesforce a little
11
+ easier.}
12
+ s.email = ["rob.rasmussen@gmail.com"]
13
+ s.extra_rdoc_files = ["Manifest.txt", "README.markdown"]
14
+ s.files = ["Manifest.txt", "README.markdown", "Rakefile", "levene.gemspec", "lib/levene.rb", "lib/levene/version.rb", "lib/levene/connection.rb", "lib/levene/models/account.rb", "lib/levene/models/base.rb", "lib/levene/models/campaign.rb", "lib/levene/models/campaign_member.rb", "lib/levene/models/contact.rb", "lib/levene/models/lead.rb", "lib/levene/models/opportunity.rb", "lib/levene/extensions/binding.rb", "test/helper.rb", "test/test_login.rb", "test/test_lead_model.rb", "test/test_base_model.rb"]
15
+ s.homepage = %q{https://github.com/robrasmussen/levene}
16
+ s.rdoc_options = ["--main", "README.markdown"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{levene}
19
+ s.rubygems_version = %q{1.3.7}
20
+ s.summary = %q{A light wrapper around RForce to make working with Salesforce a little easier.}
21
+ s.test_files = ["test/test_base_model.rb", "test/test_lead_model.rb", "test/test_login.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
28
+ s.add_runtime_dependency(%q<activemodel>, [">= 3.0.3"])
29
+ s.add_runtime_dependency(%q<activesupport>, [">= 3.0.3"])
30
+ s.add_runtime_dependency(%q<rforce>, ["~> 0.6.0"])
31
+ s.add_development_dependency(%q<minitest>, [">= 1.6.0"])
32
+ s.add_development_dependency(%q<nokogiri>, [">= 1.4.4"])
33
+ s.add_development_dependency(%q<hoe>, [">= 2.8.0"])
34
+ else
35
+ s.add_dependency(%q<activemodel>, [">= 3.0.3"])
36
+ s.add_dependency(%q<activesupport>, [">= 3.0.3"])
37
+ s.add_dependency(%q<rforce>, ["~> 0.6.0"])
38
+ s.add_dependency(%q<minitest>, [">= 1.6.0"])
39
+ s.add_dependency(%q<nokogiri>, [">= 1.4.4"])
40
+ s.add_dependency(%q<hoe>, [">= 2.8.0"])
41
+ end
42
+ else
43
+ s.add_dependency(%q<activemodel>, [">= 3.0.3"])
44
+ s.add_dependency(%q<activesupport>, [">= 3.0.3"])
45
+ s.add_dependency(%q<rforce>, ["~> 0.6.0"])
46
+ s.add_dependency(%q<minitest>, [">= 1.6.0"])
47
+ s.add_dependency(%q<nokogiri>, [">= 1.4.4"])
48
+ s.add_dependency(%q<hoe>, [">= 2.8.0"])
49
+ end
50
+ end
@@ -0,0 +1,30 @@
1
+ module Levene
2
+ class Connection
3
+
4
+ def login(username, password)
5
+ login_result = self.binding.login username, password
6
+ true
7
+ rescue
8
+ false
9
+ end
10
+
11
+ def binding
12
+ @binding ||= ::RForce::Binding.new 'https://login.salesforce.com/services/Soap/u/20.0'
13
+ end
14
+
15
+ def start
16
+ yield binding
17
+ logout
18
+ end
19
+
20
+ def logout
21
+ self.binding.logout
22
+ @binding = nil
23
+ end
24
+
25
+ def has_session?
26
+ !self.binding.instance_variable_get("@session_id").nil?
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,46 @@
1
+ module Levene
2
+ module Extensions
3
+ module Binding
4
+
5
+ def logout
6
+ response = call_remote(:logout, [])
7
+ @session_id = nil
8
+ end
9
+
10
+ def describe(model)
11
+ result = call_remote(:describeSObject, :sObjectType => model.name.demodulize)
12
+ if result[:Fault]
13
+ raise result[:Fault][:faultstring]
14
+ else
15
+ return result[:describeSObjectResponse][:result][:fields]
16
+ end
17
+ end
18
+
19
+ def query(model, conditions)
20
+ full_query = "SELECT #{model.columns.collect {|c| c[:name]}.join(", ")} FROM #{model.model_name.demodulize} #{conditions || ""}"
21
+ result = call_remote(:query, :queryString => full_query)
22
+ if result[:Fault]
23
+ raise result[:Fault][:faultstring]
24
+ else
25
+ result[:queryResponse][:result].nil? ? [] : [result[:queryResponse][:result][:records]].flatten
26
+ end
27
+ end
28
+
29
+ def create(model)
30
+ return false unless model.valid?
31
+ result = call_remote(:create, model.to_s_object)
32
+ if result[:Fault]
33
+ raise result[:Fault][:faultstring]
34
+ else
35
+ unless result[:createResponse][:result][:id].nil?
36
+ model.id = result[:createResponse][:result][:id]
37
+ return true
38
+ else
39
+ model.errors.add_to_base(result[:createResponse][:result][:errors][:message])
40
+ return false
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,6 @@
1
+ module Levene
2
+ module Models
3
+ class Account < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,140 @@
1
+ require 'active_model'
2
+ require 'active_support/core_ext/class/attribute'
3
+
4
+ module Levene
5
+ module Models
6
+ class Base
7
+ extend ActiveModel::Naming
8
+ include ActiveModel::Validations
9
+
10
+ class_attribute :connection
11
+
12
+ def attributes
13
+ self.class.attr_names.inject({}) do |memo, name|
14
+ memo[name] = self.send(name)
15
+ memo
16
+ end
17
+ end
18
+
19
+ def attributes=(attrs)
20
+ attrs.each do |attr, val|
21
+ if attr[0] == attr[0].upcase
22
+ attr = attr.to_s.underscore
23
+ attr = attr[0].downcase + attr[1..-1]
24
+ end
25
+
26
+ if attr == "id" && Array === val
27
+ val = val.first
28
+ end
29
+
30
+ self.send "#{attr}=", val if self.respond_to?("#{attr}=".to_sym)
31
+ end
32
+ end
33
+
34
+ def save
35
+ if self.id.nil?
36
+ self.connection.binding.create(self)
37
+ else
38
+ self.connection.binding.update(self)
39
+ end
40
+ end
41
+
42
+ def to_s_object
43
+ attributeMap = self.attributes.inject({}) do |memo, attr|
44
+ next memo if attr.last.nil? || attr.last.blank?
45
+ levene_attr_name = attr.first.to_s.camelize
46
+ if attr.first.to_s.ends_with?("__c")
47
+ levene_attr_name.gsub!(/_c$/, "__c")
48
+ end
49
+ memo[levene_attr_name] = attr.last
50
+ memo
51
+ end
52
+
53
+ fieldsToNull = self.attributes.select {|k,v| self.class.column_hash[k][:createable] == "true" && (v.nil? || v.blank?)}.collect {|k,v| k.to_s.camelize}
54
+ fieldsToNull = fieldsToNull.collect {|k| k[0].downcase + k[1..-1]}
55
+
56
+ {:sObject => {"xsi:type" => self.class.model_name.demodulize}.merge(attributeMap)}
57
+ end
58
+
59
+ class << self
60
+ attr_accessor :abstract
61
+ alias_method :abstract?, :abstract
62
+ attr_accessor :columns
63
+ attr_accessor :attr_names
64
+ attr_accessor :column_hash
65
+
66
+ def abstract!
67
+ self.abstract = true
68
+ end
69
+
70
+ def inherited(klazz)
71
+ klazz.abstract = false
72
+ klazz.get_column_definitions
73
+ end
74
+
75
+ def find(*ids)
76
+ results = self.connection.find(self,ids)
77
+ end
78
+
79
+ def find_by_soql(query)
80
+ result = self.connection.binding.query(self, query)
81
+ return [] if result == [nil]
82
+ result.collect {|r| obj = self.new; obj.attributes = r; obj}
83
+ end
84
+
85
+ def get_column_definitions
86
+ self.columns = self.connection.binding.describe(self)
87
+ self.columns.each do |col|
88
+ next if col[:deprecatedAndHidden] == "true"
89
+
90
+ attribute = (col[:name][0].downcase + col[:name][1..-1]).underscore
91
+ self.attr_names ||= []
92
+ self.attr_names << attribute.to_sym
93
+ self.column_hash ||= {}
94
+ self.column_hash[attribute.to_sym] = col
95
+
96
+ attr_accessor attribute
97
+
98
+ if col[:nillable] == "false" && col[:createable] == "true" && col[:defaultedOnCreate] != "true"
99
+ validates_presence_of attribute
100
+ end
101
+
102
+ if col[:type] == "string" && col[:length] && col[:length].to_i > 0
103
+ validates_length_of attribute, :maximum => col[:length].to_i
104
+ end
105
+
106
+ if col[:picklistValues]
107
+ valid_values = col[:picklistValues].select {|h| h[:active] == "true"}.collect {|h| h[:value]}
108
+ default = col[:picklistValues].find {|h| h[:defaultValue] == "true"}
109
+ if col[:nillable] == "true" || col[:createable] == "false"
110
+ validates_inclusion_of attribute, :in => valid_values, :allow_nil => true
111
+ else
112
+ validates_inclusion_of attribute, :in => valid_values
113
+ end
114
+
115
+ if default
116
+ class_eval """def #{attribute}
117
+ @#{attribute} ||= \"#{default[:value]}\"
118
+ end"""
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ def connection_established?
125
+ !connection.nil? && connection.has_session?
126
+ end
127
+
128
+ def establish_connection
129
+ self.connection = Levene::Connection.new
130
+ self.connection.login ENV["SALESFORCE_DEV_USER"], ENV["SALESFORCE_DEV_PASS"]
131
+ end
132
+
133
+ end
134
+
135
+ abstract!
136
+ establish_connection
137
+
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,6 @@
1
+ module Levene
2
+ module Models
3
+ class Campaign < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Levene
2
+ module Models
3
+ class CampaignMember < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Levene
2
+ module Models
3
+ class Contact < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Levene
2
+ module Models
3
+ class Lead < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Levene
2
+ module Models
3
+ class Opportunity < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module Levene
2
+ VERSION = "0.0.1"
3
+ end
data/lib/levene.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'rforce'
2
+ require 'active_support'
3
+
4
+ module Levene
5
+ autoload :Connection, "levene/connection.rb"
6
+ module Models
7
+ autoload :Base, "levene/models/base.rb"
8
+ autoload :Account, "levene/models/account.rb"
9
+ autoload :Campaign, "levene/models/campaign.rb"
10
+ autoload :CampaignMember, "levene/models/campaign_member.rb"
11
+ autoload :Contact, "levene/models/contact.rb"
12
+ autoload :Lead, "levene/models/lead.rb"
13
+ autoload :Opportunity, "levene/models/opportunity.rb"
14
+
15
+ end
16
+ module Extensions
17
+ autoload :Binding, "levene/extensions/binding.rb"
18
+ end
19
+ end
20
+
21
+ RForce::Binding.send(:include, Levene::Extensions::Binding)
data/test/helper.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'minitest/autorun'
3
+ require 'levene'
4
+
5
+ class Object
6
+ def must_be_true
7
+ must_equal true
8
+ end
9
+
10
+ def must_be_false
11
+ must_equal false
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ require 'helper'
2
+
3
+ describe Levene::Models::Base do
4
+
5
+ it "should be abstract" do
6
+ Levene::Models::Base.abstract?.must_be_true
7
+ end
8
+ end
@@ -0,0 +1,29 @@
1
+ require 'helper'
2
+
3
+ describe Levene::Models::Lead do
4
+ before do
5
+ @lead = Levene::Models::Lead.new
6
+ end
7
+
8
+ it "should conform to ActiveModel::Naming" do
9
+ @lead.class.model_name.must_equal "Levene::Models::Lead"
10
+ @lead.class.model_name.human.must_equal "Lead"
11
+ end
12
+
13
+ it "should not be abstract" do
14
+ @lead.class.abstract?.must_be_false
15
+ end
16
+
17
+ it "should have a list of columns" do
18
+ @lead.class.columns.count.must_be :>, 0
19
+ end
20
+
21
+ it "should have a connection attribute" do
22
+ @lead.class.must_respond_to :connection
23
+ end
24
+
25
+ it "should respond to #save" do
26
+ @lead.must_respond_to :save
27
+ end
28
+
29
+ end
@@ -0,0 +1,66 @@
1
+ require 'helper'
2
+
3
+ describe Levene::Connection do
4
+ before do
5
+ @connection = Levene::Connection.new
6
+ end
7
+
8
+ it "must respond to #login" do
9
+ @connection.must_respond_to :login
10
+ end
11
+
12
+ it "must respond to #binding" do
13
+ @connection.must_respond_to :binding
14
+ end
15
+
16
+ describe "with valid user credentials" do
17
+ before do
18
+ @username = ENV["SALESFORCE_DEV_USER"]
19
+ @password = ENV["SALESFORCE_DEV_PASS"]
20
+ end
21
+
22
+ it "should return a truthy value for a successful login" do
23
+ assert @connection.login(@username, @password), "Successful login should return something truthy"
24
+ end
25
+
26
+ it "should report is has a ssession after a successful login" do
27
+ @connection.login(@username, @password)
28
+ @connection.has_session?.must_be_true
29
+ end
30
+ end
31
+
32
+ describe "with invalid user credentials" do
33
+ before do
34
+ @username= "foo"
35
+ @password = "bar"
36
+ end
37
+
38
+ it "should return false for an unsuccessful login" do
39
+ assert !@connection.login(@username, @password), "Unsuccessful login should return someing falsy"
40
+ end
41
+
42
+ it "should not have a session after an unsuccessful login" do
43
+ @connection.login(@username, @password)
44
+ assert @connection.has_session?.must_be_false
45
+ end
46
+ end
47
+
48
+
49
+ describe "a logged in connection" do
50
+ before do
51
+ @connection.login(ENV["SALESFORCE_DEV_USER"], ENV["SALESFORCE_DEV_PASS"])
52
+ end
53
+
54
+ it "should yield a levene binding from start" do
55
+ @connection.start do |binding|
56
+ binding.must_be_kind_of RForce::Binding
57
+ @connection.has_session?.must_be_true
58
+ end
59
+ end
60
+
61
+ it "should not have an active binding after the block finished" do
62
+ @connection.start {|binding| }
63
+ @connection.has_session?.must_be_false
64
+ end
65
+ end
66
+ end
metadata ADDED
@@ -0,0 +1,178 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: levene
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Robert Rasmussen
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-20 00:00:00 -06:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activemodel
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 3
30
+ - 0
31
+ - 3
32
+ version: 3.0.3
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: activesupport
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 3
45
+ - 0
46
+ - 3
47
+ version: 3.0.3
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: rforce
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ~>
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 0
60
+ - 6
61
+ - 0
62
+ version: 0.6.0
63
+ type: :runtime
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: minitest
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 1
75
+ - 6
76
+ - 0
77
+ version: 1.6.0
78
+ type: :development
79
+ version_requirements: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ name: nokogiri
82
+ prerelease: false
83
+ requirement: &id005 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 1
90
+ - 4
91
+ - 4
92
+ version: 1.4.4
93
+ type: :development
94
+ version_requirements: *id005
95
+ - !ruby/object:Gem::Dependency
96
+ name: hoe
97
+ prerelease: false
98
+ requirement: &id006 !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ segments:
104
+ - 2
105
+ - 8
106
+ - 0
107
+ version: 2.8.0
108
+ type: :development
109
+ version_requirements: *id006
110
+ description: |-
111
+ A light wrapper around RForce to make working with Salesforce a little
112
+ easier.
113
+ email:
114
+ - rob.rasmussen@gmail.com
115
+ executables: []
116
+
117
+ extensions: []
118
+
119
+ extra_rdoc_files:
120
+ - Manifest.txt
121
+ - README.markdown
122
+ files:
123
+ - Manifest.txt
124
+ - README.markdown
125
+ - Rakefile
126
+ - levene.gemspec
127
+ - lib/levene.rb
128
+ - lib/levene/version.rb
129
+ - lib/levene/connection.rb
130
+ - lib/levene/models/account.rb
131
+ - lib/levene/models/base.rb
132
+ - lib/levene/models/campaign.rb
133
+ - lib/levene/models/campaign_member.rb
134
+ - lib/levene/models/contact.rb
135
+ - lib/levene/models/lead.rb
136
+ - lib/levene/models/opportunity.rb
137
+ - lib/levene/extensions/binding.rb
138
+ - test/helper.rb
139
+ - test/test_login.rb
140
+ - test/test_lead_model.rb
141
+ - test/test_base_model.rb
142
+ has_rdoc: true
143
+ homepage: https://github.com/robrasmussen/levene
144
+ licenses: []
145
+
146
+ post_install_message:
147
+ rdoc_options:
148
+ - --main
149
+ - README.markdown
150
+ require_paths:
151
+ - lib
152
+ required_ruby_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ segments:
158
+ - 0
159
+ version: "0"
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ segments:
166
+ - 0
167
+ version: "0"
168
+ requirements: []
169
+
170
+ rubyforge_project: levene
171
+ rubygems_version: 1.3.7
172
+ signing_key:
173
+ specification_version: 3
174
+ summary: A light wrapper around RForce to make working with Salesforce a little easier.
175
+ test_files:
176
+ - test/test_base_model.rb
177
+ - test/test_lead_model.rb
178
+ - test/test_login.rb