active_force 0.4.2 → 0.5.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 +4 -4
- data/CHANGELOG.md +65 -6
- data/README.md +12 -4
- data/lib/active_force/active_query.rb +7 -8
- data/lib/active_force/association/association.rb +4 -3
- data/lib/active_force/association/belongs_to_association.rb +5 -5
- data/lib/active_force/association/has_many_association.rb +5 -5
- data/lib/active_force/sobject.rb +110 -51
- data/lib/active_force/version.rb +1 -1
- data/lib/generators/active_force/active_force_model/active_force_model_generator.rb +40 -15
- data/lib/generators/active_force/active_force_model/templates/model.rb.erb +2 -13
- data/spec/active_force/active_query_spec.rb +42 -7
- data/spec/active_force/association_spec.rb +29 -23
- data/spec/active_force/query_spec.rb +22 -33
- data/spec/active_force/sobject/table_name_spec.rb +8 -0
- data/spec/active_force/sobject_spec.rb +54 -24
- data/spec/active_force_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -0
- data/spec/support/whizbang.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fc8bc2425de35aa52c303eb28a9165a2601c5f5
|
4
|
+
data.tar.gz: b397002aa1906d23b92d4d20ff08745d349c6cb4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef355901a29bd4ff95bf593400f3a52e32e53cd4bec886b5d057984a31092f832b0ce0cf4608462f6379652ad91120d4437100177d4f3912e0051a85abbfa9fb
|
7
|
+
data.tar.gz: 8ce4758557b84eef8662c8f53ff3e301ecdc077d1f824ef2850cb17636d6dde5cab9ed564ca57d3b02ed9a600a188b6e133ebb6eefa8f536803d3a767abcf672
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,70 @@
|
|
1
|
-
#
|
1
|
+
# Changelog
|
2
2
|
|
3
|
-
|
4
|
-
* Implement .all and .create methods (copying ActiveRecord Interface)
|
5
|
-
* Add SObject.all method.
|
6
|
-
* Add basic support for multi-picklists.
|
3
|
+
## Not released
|
7
4
|
|
8
|
-
|
5
|
+
## 0.5.0
|
6
|
+
|
7
|
+
* Provide a default id field for all SObject subclassees ([Dan Olson][], [#30][])
|
8
|
+
* Fix Ruby 2.0 compatibility issue ([Dan Olson][], [Pablo Oldani][], [#28][])
|
9
|
+
* Normalize rspec syntax to remove deprecation warnings ([Dan Olson][], [#26][])
|
10
|
+
* Remove namespace when inferring default SObject.table_name ([Dan Olson][], [#24][])
|
11
|
+
* Add create! and save! methods. ([Pablo Oldani][], [#21][])
|
12
|
+
* Refactor update and create methods. ([Pablo Oldani][], [#21][])
|
13
|
+
* Add a generator. ([José Piccioni][], [#19][])
|
14
|
+
* ActiveQuery now provides :each, :map and :inspect. ([Armando Andini][])
|
15
|
+
* Add SObject.create class mehtod. ([Pablo Oldani][], [#10][])
|
16
|
+
* SObject.field default mapping value follows SFDC API naming convention.
|
17
|
+
([Dan Olson][], [#14][] [#15][])
|
18
|
+
|
19
|
+
## 0.4.2
|
20
|
+
|
21
|
+
* Use ActiveQuery instead of Query. ([Armando Andini][])
|
22
|
+
* Add instructions to use validations ([José Piccioni][])
|
23
|
+
* Lots of refactoring.
|
24
|
+
|
25
|
+
## 0.3.2
|
26
|
+
|
27
|
+
* Fixed gemspec.
|
28
|
+
|
29
|
+
## 0.3.1
|
30
|
+
|
31
|
+
* Create different classes for associations. ([#4][])
|
32
|
+
* Big refactor on has_many association. ([Armando Andini][])
|
33
|
+
* Add a lot of specs and refactors. ([Armando Andini][])
|
34
|
+
* Add a Finders module. ([Armando Andini][])
|
35
|
+
* Add fist and last method to SObject.
|
36
|
+
|
37
|
+
## 0.2.0
|
38
|
+
|
39
|
+
* Add belogns_to and has_many associations.
|
40
|
+
* Changed when the SOQL query is sent to the client.
|
41
|
+
* Add join method to query to use associtations.
|
42
|
+
|
43
|
+
## 0.1.0
|
44
|
+
|
45
|
+
* Add query builder object to chain conditions.
|
46
|
+
* Update update and create methods.
|
47
|
+
* Add Campaing standard table name.
|
48
|
+
|
49
|
+
## 0.0.6.alfa
|
9
50
|
|
10
51
|
* ActiveForce::SObject#table_name is auto populated using the class
|
11
52
|
name. It adds "__c" to all non standard types.
|
53
|
+
|
54
|
+
<!--- The following link definition list is generated by PimpMyChangelog --->
|
55
|
+
|
56
|
+
[#4]: https://github.com/ionia-corporation/active_force/issues/4
|
57
|
+
[#9]: https://github.com/ionia-corporation/active_force/issues/9
|
58
|
+
[#10]: https://github.com/ionia-corporation/active_force/issues/10
|
59
|
+
[#14]: https://github.com/ionia-corporation/active_force/issues/14
|
60
|
+
[#15]: https://github.com/ionia-corporation/active_force/issues/15
|
61
|
+
[#19]: https://github.com/ionia-corporation/active_force/issues/19
|
62
|
+
[#21]: https://github.com/ionia-corporation/active_force/issues/21
|
63
|
+
[#24]: https://github.com/ionia-corporation/active_force/issues/24
|
64
|
+
[#26]: https://github.com/ionia-corporation/active_force/issues/26
|
65
|
+
[#28]: https://github.com/ionia-corporation/active_force/issues/28
|
66
|
+
[#30]: https://github.com/ionia-corporation/active_force/issues/30
|
67
|
+
[Pablo Oldani]: https://github.com/olvap
|
68
|
+
[Armando Andini]: https://github.com/antico5
|
69
|
+
[José Piccioni]: https://github.com/lmhsjackson
|
70
|
+
[Dan Olson]: https://github.com/DanOlson
|
data/README.md
CHANGED
@@ -7,8 +7,11 @@
|
|
7
7
|
|
8
8
|
# ActiveForce
|
9
9
|
|
10
|
-
A ruby gem to interact with SalesForce as if it were Active Record. It
|
11
|
-
uses Restforce to interact with the API, so it is fast and stable.
|
10
|
+
A ruby gem to interact with [SalesForce][1] as if it were Active Record. It
|
11
|
+
uses [Restforce][2] to interact with the API, so it is fast and stable.
|
12
|
+
|
13
|
+
[1]: http://www.salesforce.com
|
14
|
+
[2]: https://github.com/ejholmes/restforce
|
12
15
|
|
13
16
|
## Installation
|
14
17
|
|
@@ -43,17 +46,19 @@ end
|
|
43
46
|
```
|
44
47
|
|
45
48
|
### Add Attributes
|
49
|
+
|
46
50
|
```ruby
|
47
51
|
class Page < ActiveForce::SObject
|
48
52
|
#field, :attribute_name, from: 'Name_In_Salesforce_Database'
|
49
53
|
field :id, from: 'Id'
|
50
54
|
field :name, from: 'Medication__c'
|
51
|
-
self.fields = mappings.values
|
52
55
|
#set SalesForce table name.
|
53
56
|
self.table_name = 'Patient_Medication__c'
|
54
57
|
end
|
55
58
|
```
|
59
|
+
|
56
60
|
### Validations
|
61
|
+
|
57
62
|
You can use any validation that active record has (except for validates_associated), just by adding them to your class:
|
58
63
|
|
59
64
|
```ruby
|
@@ -96,6 +101,7 @@ end
|
|
96
101
|
```
|
97
102
|
|
98
103
|
#### Belongs to
|
104
|
+
|
99
105
|
```ruby
|
100
106
|
class Account < ActiveForce::SObject
|
101
107
|
end
|
@@ -112,4 +118,6 @@ end
|
|
112
118
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
113
119
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
114
120
|
4. Push to the branch (`git push origin my-new-feature`)
|
115
|
-
5. Create new Pull Request
|
121
|
+
5. Create new Pull Request so we can talk about it.
|
122
|
+
6. Once accepted, please add an entry in the CHANGELOG and rebase your changes
|
123
|
+
to squash typos or corrections.
|
@@ -1,11 +1,14 @@
|
|
1
1
|
require 'active_force/query'
|
2
|
+
require 'forwardable'
|
2
3
|
|
3
4
|
module ActiveForce
|
4
5
|
class ActiveQuery < Query
|
6
|
+
extend Forwardable
|
5
7
|
|
6
8
|
attr_reader :sobject
|
7
9
|
|
8
|
-
|
10
|
+
def_delegators :sobject, :sfdc_client, :build, :table_name, :mappings
|
11
|
+
def_delegators :to_a, :each, :map, :inspect
|
9
12
|
|
10
13
|
def initialize sobject
|
11
14
|
@sobject = sobject
|
@@ -14,20 +17,16 @@ module ActiveForce
|
|
14
17
|
end
|
15
18
|
|
16
19
|
def to_a
|
17
|
-
result.to_a.map
|
18
|
-
build mash
|
19
|
-
end
|
20
|
+
result.to_a.map { |mash| build mash }
|
20
21
|
end
|
21
22
|
|
23
|
+
alias_method :all, :to_a
|
24
|
+
|
22
25
|
def count
|
23
26
|
super
|
24
27
|
sfdc_client.query(to_s).first.expr0
|
25
28
|
end
|
26
29
|
|
27
|
-
def all
|
28
|
-
to_a
|
29
|
-
end
|
30
|
-
|
31
30
|
def limit limit
|
32
31
|
super
|
33
32
|
limit == 1 ? to_a.first : self
|
@@ -15,15 +15,16 @@ module ActiveForce
|
|
15
15
|
@options[:model] || @relation_name.to_s.singularize.camelcase.constantize
|
16
16
|
end
|
17
17
|
|
18
|
+
def foreign_key
|
19
|
+
@options[:foreign_key] || default_foreign_key
|
20
|
+
end
|
21
|
+
|
18
22
|
private
|
19
23
|
|
20
24
|
def build
|
21
25
|
define_relation_method
|
22
26
|
end
|
23
27
|
|
24
|
-
def default_sfdc_foreign_key
|
25
|
-
relation_model.mappings["#{ @parent.name.downcase }_id".to_sym]
|
26
|
-
end
|
27
28
|
end
|
28
29
|
|
29
30
|
end
|
@@ -3,16 +3,16 @@ module ActiveForce
|
|
3
3
|
|
4
4
|
class BelongsToAssociation < Association
|
5
5
|
|
6
|
-
def foreign_key
|
7
|
-
options[:foreign_key] || "#{ @relation_name }_id".to_sym
|
8
|
-
end
|
9
|
-
|
10
6
|
private
|
11
7
|
|
8
|
+
def default_foreign_key
|
9
|
+
"#{ relation_model.name.downcase }_id".to_sym
|
10
|
+
end
|
11
|
+
|
12
12
|
def define_relation_method
|
13
13
|
association = self
|
14
14
|
@parent.send :define_method, @relation_name do
|
15
|
-
association.relation_model.find(
|
15
|
+
association.relation_model.find(send association.foreign_key)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -2,18 +2,18 @@ module ActiveForce
|
|
2
2
|
module Association
|
3
3
|
class HasManyAssociation < Association
|
4
4
|
|
5
|
-
def foreign_key
|
6
|
-
@options[:foreign_key] || default_sfdc_foreign_key || @parent.table_name
|
7
|
-
end
|
8
|
-
|
9
5
|
private
|
10
6
|
|
7
|
+
def default_foreign_key
|
8
|
+
"#{ @parent.name.downcase }_id".to_sym
|
9
|
+
end
|
10
|
+
|
11
11
|
def define_relation_method
|
12
12
|
association = self
|
13
13
|
@parent.send :define_method, @relation_name do
|
14
14
|
query = association.relation_model.query
|
15
15
|
query.options association.options
|
16
|
-
query.where
|
16
|
+
query.where association.foreign_key => self.id
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
data/lib/active_force/sobject.rb
CHANGED
@@ -4,25 +4,59 @@ require 'active_attr/dirty'
|
|
4
4
|
require 'active_force/active_query'
|
5
5
|
require 'active_force/association'
|
6
6
|
require 'yaml'
|
7
|
+
require 'forwardable'
|
8
|
+
require 'logger'
|
9
|
+
|
7
10
|
|
8
11
|
module ActiveForce
|
9
12
|
class SObject
|
10
13
|
include ActiveAttr::Model
|
11
14
|
include ActiveAttr::Dirty
|
12
15
|
include ActiveForce::Association
|
13
|
-
|
14
16
|
STANDARD_TYPES = %w[ Account Contact Opportunity Campaign]
|
15
17
|
|
16
|
-
class_attribute :mappings, :
|
18
|
+
class_attribute :mappings, :table_name
|
17
19
|
|
18
20
|
class << self
|
19
|
-
|
21
|
+
extend Forwardable
|
22
|
+
def_delegators :query, :where, :first, :last, :all, :find, :find_by, :count
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
###
|
27
|
+
# Transforms +attribute+ to the conventional Salesforce API name.
|
28
|
+
#
|
29
|
+
# Example:
|
30
|
+
# > default_api_name :some_attribute
|
31
|
+
# => "Some_Attribute__c"
|
32
|
+
def default_api_name(attribute)
|
33
|
+
String(attribute).split('_').map(&:capitalize).join('_') << '__c'
|
34
|
+
end
|
35
|
+
|
36
|
+
def custom_table_name
|
37
|
+
self.name if STANDARD_TYPES.include? self.name
|
38
|
+
end
|
39
|
+
|
40
|
+
###
|
41
|
+
# Provide each subclass with a default id field. Can be overridden
|
42
|
+
# in the subclass if needed
|
43
|
+
def inherited(subclass)
|
44
|
+
subclass.field :id, from: 'Id'
|
45
|
+
end
|
20
46
|
end
|
21
47
|
|
22
48
|
# The table name to used to make queries.
|
23
49
|
# It is derived from the class name adding the "__c" when needed.
|
24
50
|
def self.table_name
|
25
|
-
@table_name ||= custom_table_name || "#{ self.name }__c"
|
51
|
+
@table_name ||= custom_table_name || "#{ self.name.split('::').last }__c"
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.fields
|
55
|
+
mappings.values
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.query
|
59
|
+
ActiveForce::ActiveQuery.new self
|
26
60
|
end
|
27
61
|
|
28
62
|
def self.build sf_table_description
|
@@ -35,53 +69,41 @@ module ActiveForce
|
|
35
69
|
sobject
|
36
70
|
end
|
37
71
|
|
38
|
-
def self.query
|
39
|
-
ActiveForce::ActiveQuery.new self
|
40
|
-
end
|
41
|
-
|
42
72
|
def update_attributes! attributes = {}
|
43
73
|
assign_attributes attributes
|
44
74
|
return false unless valid?
|
45
|
-
|
46
|
-
changed.each do |field|
|
47
|
-
sobject_hash[mappings[field.to_sym]] = read_attribute(field)
|
48
|
-
end
|
49
|
-
result = sfdc_client.update! table_name, sobject_hash
|
75
|
+
sfdc_client.update! table_name, attributes_for_sfdb_update
|
50
76
|
changed_attributes.clear
|
51
|
-
|
77
|
+
self
|
52
78
|
end
|
53
79
|
|
54
80
|
def update_attributes attributes = {}
|
55
81
|
update_attributes! attributes
|
56
82
|
rescue Faraday::Error::ClientError => error
|
57
|
-
|
58
|
-
"[SFDC] [#{self.class.model_name}] [#{self.class.table_name}] Error while updating, params: #{hash}, error: #{error.inspect}"
|
59
|
-
end
|
60
|
-
errors[:base] << error.message
|
61
|
-
false
|
83
|
+
logger_output __method__
|
62
84
|
end
|
63
85
|
|
64
86
|
alias_method :update, :update_attributes
|
65
87
|
|
66
88
|
def create!
|
67
89
|
return false unless valid?
|
68
|
-
|
69
|
-
mappings.map do |field, name_in_sfdc|
|
70
|
-
value = read_value field
|
71
|
-
hash[name_in_sfdc] = value if value.present?
|
72
|
-
end
|
73
|
-
self.id = sfdc_client.create! table_name, hash
|
90
|
+
self.id = sfdc_client.create! table_name, attributes_for_sfdb_create
|
74
91
|
changed_attributes.clear
|
92
|
+
self
|
75
93
|
end
|
76
94
|
|
77
95
|
def create
|
78
96
|
create!
|
79
97
|
rescue Faraday::Error::ClientError => error
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
98
|
+
logger_output __method__
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.create args
|
102
|
+
new(args).save
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.create! args
|
106
|
+
new(args).save!
|
85
107
|
end
|
86
108
|
|
87
109
|
def save
|
@@ -92,6 +114,14 @@ module ActiveForce
|
|
92
114
|
end
|
93
115
|
end
|
94
116
|
|
117
|
+
def save!
|
118
|
+
if persisted?
|
119
|
+
update_attributes!
|
120
|
+
else
|
121
|
+
create!
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
95
125
|
def to_param
|
96
126
|
id
|
97
127
|
end
|
@@ -100,43 +130,72 @@ module ActiveForce
|
|
100
130
|
id?
|
101
131
|
end
|
102
132
|
|
103
|
-
def self.field field_name,
|
104
|
-
|
105
|
-
|
133
|
+
def self.field field_name, args = {}
|
134
|
+
args[:from] ||= default_api_name(field_name)
|
135
|
+
args[:as] ||= :string
|
136
|
+
mappings[field_name] = args[:from]
|
137
|
+
attribute field_name, sf_type: args[:as]
|
106
138
|
end
|
107
139
|
|
108
140
|
def self.mappings
|
109
141
|
@mappings ||= {}
|
110
142
|
end
|
111
143
|
|
112
|
-
|
113
144
|
private
|
114
145
|
|
115
|
-
def
|
116
|
-
|
146
|
+
def logger_output action
|
147
|
+
logger = Logger.new(STDOUT)
|
148
|
+
logger.info("[SFDC] [#{self.class.model_name}] [#{self.class.table_name}] Error while #{ action }, params: #{hash}, error: #{error.inspect}")
|
149
|
+
errors[:base] << error.message
|
150
|
+
false
|
117
151
|
end
|
118
152
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
attribute(field.to_s)
|
124
|
-
end
|
153
|
+
def attributes_for_sfdb_create
|
154
|
+
attrs = mappings.map do |attr, sf_field|
|
155
|
+
value = read_attribute(attr)
|
156
|
+
[sf_field, value] if value
|
125
157
|
end
|
158
|
+
Hash.new(attrs.compact)
|
159
|
+
end
|
160
|
+
|
126
161
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
[value[:label], value[:value]]
|
131
|
-
end
|
162
|
+
def attributes_for_sfdb_update
|
163
|
+
attrs = changed_mappings.map do |attr, sf_field|
|
164
|
+
[sf_field, read_attribute(attr)]
|
132
165
|
end
|
166
|
+
Hash.new(attrs).merge('Id' => id)
|
167
|
+
end
|
168
|
+
|
169
|
+
def changed_mappings
|
170
|
+
mappings.select { |attr, sf_field| changed.include? attr.to_s}
|
171
|
+
end
|
133
172
|
|
134
|
-
|
135
|
-
|
173
|
+
def read_value field
|
174
|
+
case sf_field_type field
|
175
|
+
when :multi_picklist
|
176
|
+
attribute(field.to_s).reject(&:empty?).join(';')
|
177
|
+
else
|
178
|
+
attribute(field.to_s)
|
136
179
|
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def sf_field_type field
|
183
|
+
self.class.attributes[field][:sf_tpye]
|
184
|
+
end
|
137
185
|
|
138
|
-
|
139
|
-
|
186
|
+
def self.picklist field
|
187
|
+
picks = sfdc_client.picklist_values(table_name, mappings[field])
|
188
|
+
picks.map do |value|
|
189
|
+
[value[:label], value[:value]]
|
140
190
|
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def self.sfdc_client
|
194
|
+
@client ||= Restforce.new
|
195
|
+
end
|
196
|
+
|
197
|
+
def sfdc_client
|
198
|
+
self.class.sfdc_client
|
199
|
+
end
|
141
200
|
end
|
142
201
|
end
|
data/lib/active_force/version.rb
CHANGED
@@ -1,22 +1,47 @@
|
|
1
|
-
|
1
|
+
module ActiveForce
|
2
|
+
class ActiveForceModelGenerator < Rails::Generators::NamedBase
|
2
3
|
|
3
|
-
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
5
|
|
5
|
-
|
6
|
-
argument :attributes, type: :array, default: [],
|
7
|
-
banner: "field[:sales_force_name] field[:sales_force_name]"
|
6
|
+
def create_model_file
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
sf_field_names = list_field_names file_name.capitalize
|
9
|
+
@attributes = create_attributes sf_field_names
|
10
|
+
|
11
|
+
template "model.rb.erb", "app/models/#{file_name}.rb"
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
+
protected
|
15
|
+
|
16
|
+
Attribute = Struct.new(:local_name, :remote_name)
|
17
|
+
|
18
|
+
def create_attributes sf_field_names
|
19
|
+
sf_field_names.map do |field|
|
20
|
+
Attribute.new( sf_name_to_symbol(field) ,field)
|
21
|
+
end
|
22
|
+
end
|
14
23
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
Attribute.new name, remote_name
|
24
|
+
def list_field_names table_name
|
25
|
+
Client.describe(table_name).fields.map do |field|
|
26
|
+
field.name
|
27
|
+
end
|
20
28
|
end
|
29
|
+
|
30
|
+
def sf_name_to_symbol sf_name
|
31
|
+
sf_name = sf_name.underscore
|
32
|
+
sf_name = sf_name[0..-4] if sf_name.include? "__c"
|
33
|
+
sf_name.to_sym
|
34
|
+
end
|
35
|
+
|
36
|
+
class String
|
37
|
+
def underscore
|
38
|
+
self.gsub(/::/, '/').
|
39
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
40
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
41
|
+
tr("-", "_").
|
42
|
+
downcase
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
21
46
|
end
|
22
|
-
end
|
47
|
+
end
|
@@ -2,21 +2,10 @@ require 'active_force/sobject'
|
|
2
2
|
|
3
3
|
class <%= class_name %> < ActiveForce::SObject
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
<%= attribute.local_name %>: '<%= attribute.remote_name %>',
|
5
|
+
<% @attributes.each do |attribute| -%>
|
6
|
+
field :<%= attribute.local_name %>, from: '<%= attribute.remote_name %>',
|
8
7
|
<% end -%>
|
9
|
-
id: 'Id'
|
10
|
-
}
|
11
|
-
FIELDS = MAPPINGS.values
|
12
|
-
RELATED_LIST_FIELDS = FIELDS
|
13
8
|
|
14
|
-
self.mappings = MAPPINGS
|
15
|
-
self.fields = FIELDS
|
16
9
|
self.table_name = '<%= class_name %>'
|
17
10
|
|
18
|
-
<% attributes.each do |attribute| -%>
|
19
|
-
attribute :<%= attribute.local_name %>
|
20
|
-
<% end -%>
|
21
|
-
|
22
11
|
end
|
@@ -4,8 +4,9 @@ require 'active_force/active_query'
|
|
4
4
|
describe ActiveForce::ActiveQuery do
|
5
5
|
let(:sobject){
|
6
6
|
sobject = double("sobject")
|
7
|
-
sobject.
|
8
|
-
sobject.
|
7
|
+
allow(sobject).to receive(:table_name).and_return "table_name"
|
8
|
+
allow(sobject).to receive(:fields).and_return []
|
9
|
+
allow(sobject).to receive(:mappings).and_return({field: "Field__c"})
|
9
10
|
sobject
|
10
11
|
}
|
11
12
|
|
@@ -13,10 +14,11 @@ describe ActiveForce::ActiveQuery do
|
|
13
14
|
double("client")
|
14
15
|
}
|
15
16
|
|
17
|
+
let(:active_query){ ActiveForce::ActiveQuery.new(sobject) }
|
18
|
+
|
16
19
|
before do
|
17
|
-
|
18
|
-
|
19
|
-
@active_query.stub(:build).and_return Object.new
|
20
|
+
allow(active_query).to receive(:sfdc_client).and_return client
|
21
|
+
allow(active_query).to receive(:build).and_return Object.new
|
20
22
|
end
|
21
23
|
|
22
24
|
describe "to_a" do
|
@@ -25,14 +27,47 @@ describe ActiveForce::ActiveQuery do
|
|
25
27
|
end
|
26
28
|
|
27
29
|
it "should return an array of objects" do
|
28
|
-
result =
|
30
|
+
result = active_query.where("Text_Label = 'foo'").to_a
|
29
31
|
expect(result).to be_a Array
|
30
32
|
end
|
31
33
|
|
32
34
|
it "should allow to chain query methods" do
|
33
|
-
result =
|
35
|
+
result = active_query.where("Text_Label = 'foo'").where("Checkbox_Label = true").to_a
|
34
36
|
expect(result).to be_a Array
|
35
37
|
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "condition mapping" do
|
41
|
+
it "maps conditions for a .where" do
|
42
|
+
active_query.where(field: 123)
|
43
|
+
expect(active_query.to_s).to eq("SELECT Id FROM table_name WHERE Field__c = 123")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "encloses the value in quotes if it's a string" do
|
47
|
+
active_query.where field: "hello"
|
48
|
+
expect(active_query.to_s).to end_with("Field__c = 'hello'")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#find_by" do
|
53
|
+
it "should query the client, with the SFDC field names and correctly enclosed values" do
|
54
|
+
expect(client).to receive :query
|
55
|
+
active_query.find_by field: 123
|
56
|
+
expect(active_query.to_s).to eq "SELECT Id FROM table_name WHERE Field__c = 123 LIMIT 1"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "responding as an enumerable" do
|
61
|
+
before do
|
62
|
+
expect(active_query).to receive(:to_a).and_return([])
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should call to_a when receiving each" do
|
66
|
+
active_query.each {}
|
67
|
+
end
|
36
68
|
|
69
|
+
it "should call to_a when receiving map" do
|
70
|
+
active_query.map {}
|
71
|
+
end
|
37
72
|
end
|
38
73
|
end
|
@@ -5,14 +5,14 @@ describe ActiveForce::SObject do
|
|
5
5
|
|
6
6
|
let :post do
|
7
7
|
post = Post.new
|
8
|
-
post.
|
8
|
+
allow(post).to receive(:id).and_return "1"
|
9
9
|
post
|
10
10
|
end
|
11
11
|
|
12
12
|
let :comment do
|
13
13
|
comment = Comment.new
|
14
|
-
comment.
|
15
|
-
comment.
|
14
|
+
allow(comment).to receive(:id).and_return "1"
|
15
|
+
allow(comment).to receive(:post_id).and_return "1"
|
16
16
|
comment
|
17
17
|
end
|
18
18
|
|
@@ -26,10 +26,11 @@ describe ActiveForce::SObject do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
class Comment < ActiveForce::SObject
|
29
|
+
field :post_id, from: "PostId"
|
29
30
|
self.table_name = "Comment__c"
|
30
31
|
end
|
31
32
|
|
32
|
-
ActiveForce::SObject.
|
33
|
+
allow(ActiveForce::SObject).to receive(:sfdc_client).and_return client
|
33
34
|
end
|
34
35
|
|
35
36
|
describe "has_many_query" do
|
@@ -49,39 +50,41 @@ describe ActiveForce::SObject do
|
|
49
50
|
end
|
50
51
|
|
51
52
|
describe 'to_s' do
|
52
|
-
it "should retrun a
|
53
|
-
|
54
|
-
|
53
|
+
it "should retrun a SOQL statment" do
|
54
|
+
soql = "SELECT Id, PostId FROM Comment__c WHERE PostId = '1'"
|
55
|
+
expect(post.comments.to_s).to eq soql
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
58
59
|
end
|
59
60
|
|
60
61
|
describe 'has_many(options)' do
|
62
|
+
before do
|
63
|
+
Post.has_many :comments
|
64
|
+
end
|
61
65
|
|
62
66
|
it 'should allow to send a different query table name' do
|
63
67
|
Post.has_many :ugly_comments, { model: Comment }
|
64
|
-
|
65
|
-
|
68
|
+
soql = "SELECT Id, PostId FROM Comment__c WHERE PostId = '1'"
|
69
|
+
expect(post.ugly_comments.to_s).to eq soql
|
66
70
|
end
|
67
71
|
|
68
72
|
it 'should allow to change the foreign key' do
|
69
|
-
Post.has_many :comments, { foreign_key:
|
70
|
-
|
71
|
-
|
73
|
+
Post.has_many :comments, { foreign_key: :post }
|
74
|
+
Comment.field :post, from: 'PostId'
|
75
|
+
soql = "SELECT Id, PostId FROM Comment__c WHERE PostId = '1'"
|
76
|
+
expect(post.comments.to_s).to eq soql
|
72
77
|
end
|
73
78
|
|
74
79
|
it 'should allow to add a where condition' do
|
75
80
|
Post.has_many :comments, { where: '1 = 1' }
|
76
|
-
|
77
|
-
|
81
|
+
soql = "SELECT Id, PostId FROM Comment__c WHERE 1 = 1 AND PostId = '1'"
|
82
|
+
expect(post.comments.to_s).to eq soql
|
78
83
|
end
|
79
84
|
|
80
85
|
it 'should use a convention name for the foreign key' do
|
81
|
-
|
82
|
-
|
83
|
-
post.comments.to_s.should ==
|
84
|
-
"SELECT Id FROM Comment__c WHERE PostId = '1'"
|
86
|
+
soql = "SELECT Id, PostId FROM Comment__c WHERE PostId = '1'"
|
87
|
+
expect(post.comments.to_s).to eq soql
|
85
88
|
end
|
86
89
|
|
87
90
|
end
|
@@ -89,18 +92,21 @@ describe ActiveForce::SObject do
|
|
89
92
|
describe "belongs_to" do
|
90
93
|
|
91
94
|
before do
|
92
|
-
|
93
|
-
client.stub(:query).and_return Restforce::Mash.new(id: 1)
|
95
|
+
allow(client).to receive(:query).and_return [Restforce::Mash.new(id: 1)]
|
94
96
|
end
|
95
97
|
|
96
98
|
it "should get the resource it belongs to" do
|
99
|
+
Comment.belongs_to :post
|
97
100
|
expect(comment.post).to be_instance_of(Post)
|
98
101
|
end
|
99
102
|
|
100
103
|
it "should allow to pass a foreign key as options" do
|
101
|
-
Comment
|
102
|
-
|
103
|
-
|
104
|
+
class Comment < ActiveForce::SObject
|
105
|
+
field :fancy_post_id, from: 'PostId'
|
106
|
+
belongs_to :post, foreign_key: :fancy_post_id
|
107
|
+
end
|
108
|
+
allow(comment).to receive(:fancy_post_id).and_return "2"
|
109
|
+
expect(client).to receive(:query).with("SELECT Id FROM Post__c WHERE Id = '2' LIMIT 1")
|
104
110
|
comment.post
|
105
111
|
end
|
106
112
|
|
@@ -13,76 +13,74 @@ describe ActiveForce::Query do
|
|
13
13
|
|
14
14
|
describe ".all" do
|
15
15
|
it "table should return table name" do
|
16
|
-
@query.all.table.
|
16
|
+
expect(@query.all.table).to eq(@query.table)
|
17
17
|
end
|
18
18
|
|
19
19
|
it "fields should return fields" do
|
20
|
-
@query.all.fields.
|
20
|
+
expect(@query.all.fields).to eq @query.fields
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
describe ".all.to_s" do
|
25
25
|
it "should return a query for all records" do
|
26
|
-
@query.all.to_s.
|
26
|
+
expect(@query.all.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should ignore dupicated attributes in select statment" do
|
30
30
|
@query.fields ['Id', 'name', 'etc']
|
31
|
-
@query.all.to_s.
|
31
|
+
expect(@query.all.to_s).to eq "SELECT Id, name, etc FROM table_name"
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
describe ".where" do
|
36
36
|
it "should add a where condition to a query" do
|
37
|
-
@query.where("name like '%a%'").to_s.
|
37
|
+
expect(@query.where("name like '%a%'").to_s).to eq "SELECT Id, name, etc FROM table_name WHERE name like '%a%'"
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should add multiples conditions to a query" do
|
41
|
-
@query.where("condition1 = 1").where("condition2 = 2").to_s.
|
42
|
-
"SELECT Id, name, etc FROM table_name WHERE condition1 = 1 AND condition2 = 2"
|
41
|
+
expect(@query.where("condition1 = 1").where("condition2 = 2").to_s).to eq "SELECT Id, name, etc FROM table_name WHERE condition1 = 1 AND condition2 = 2"
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
46
45
|
describe ".limit" do
|
47
46
|
it "should add a limit to a query" do
|
48
|
-
@query.limit("25").to_s.
|
47
|
+
expect(@query.limit("25").to_s).to eq "SELECT Id, name, etc FROM table_name LIMIT 25"
|
49
48
|
end
|
50
49
|
end
|
51
50
|
|
52
51
|
describe ".limit_value" do
|
53
52
|
it "should return the limit value" do
|
54
53
|
@query.limit(4)
|
55
|
-
@query.limit_value.
|
54
|
+
expect(@query.limit_value).to eq 4
|
56
55
|
end
|
57
56
|
end
|
58
57
|
|
59
58
|
describe ".offset" do
|
60
59
|
it "should add an offset to a query" do
|
61
|
-
@query.offset(4).to_s.
|
60
|
+
expect(@query.offset(4).to_s).to eq "SELECT Id, name, etc FROM table_name OFFSET 4"
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
65
64
|
describe ".offset_value" do
|
66
65
|
it "should return the offset value" do
|
67
66
|
@query.offset(4)
|
68
|
-
@query.offset_value.
|
67
|
+
expect(@query.offset_value).to eq 4
|
69
68
|
end
|
70
69
|
end
|
71
70
|
|
72
71
|
describe ".find.to_s" do
|
73
72
|
it "should return a query for 1 record" do
|
74
|
-
@query.find(2).to_s.
|
73
|
+
expect(@query.find(2).to_s).to eq "SELECT Id, name, etc FROM table_name WHERE Id = '2' LIMIT 1"
|
75
74
|
end
|
76
75
|
end
|
77
76
|
|
78
77
|
describe ".order" do
|
79
78
|
it "should add a order condition in the statment" do
|
80
|
-
@query.order("name desc").to_s.
|
79
|
+
expect(@query.order("name desc").to_s).to eq "SELECT Id, name, etc FROM table_name ORDER BY name desc"
|
81
80
|
end
|
82
81
|
|
83
82
|
it "should add a order condition in the statment with WHERE and LIMIT" do
|
84
|
-
@query.where("condition1 = 1").order("name desc").limit(1).to_s.
|
85
|
-
"SELECT Id, name, etc FROM table_name WHERE condition1 = 1 ORDER BY name desc LIMIT 1"
|
83
|
+
expect(@query.where("condition1 = 1").order("name desc").limit(1).to_s).to eq "SELECT Id, name, etc FROM table_name WHERE condition1 = 1 ORDER BY name desc LIMIT 1"
|
86
84
|
end
|
87
85
|
end
|
88
86
|
|
@@ -94,56 +92,47 @@ describe ActiveForce::Query do
|
|
94
92
|
end
|
95
93
|
|
96
94
|
it 'should add another select statment on the current select' do
|
97
|
-
@query.join(@join).to_s.
|
98
|
-
'SELECT Id, name, etc, (SELECT Id, name, etc FROM join_table_name) FROM table_name'
|
95
|
+
expect(@query.join(@join).to_s).to eq 'SELECT Id, name, etc, (SELECT Id, name, etc FROM join_table_name) FROM table_name'
|
99
96
|
end
|
100
97
|
end
|
101
98
|
|
102
99
|
describe '.first' do
|
103
100
|
it 'should return the query for the first record' do
|
104
|
-
@query.first.to_s.
|
105
|
-
'SELECT Id, name, etc FROM table_name LIMIT 1'
|
101
|
+
expect(@query.first.to_s).to eq 'SELECT Id, name, etc FROM table_name LIMIT 1'
|
106
102
|
end
|
107
103
|
end
|
108
104
|
|
109
105
|
describe '.last' do
|
110
106
|
it 'should return the query for the last record' do
|
111
|
-
@query.last.to_s.
|
112
|
-
'SELECT Id, name, etc FROM table_name ORDER BY Id DESC LIMIT 1'
|
107
|
+
expect(@query.last.to_s).to eq 'SELECT Id, name, etc FROM table_name ORDER BY Id DESC LIMIT 1'
|
113
108
|
end
|
114
109
|
end
|
115
110
|
|
116
111
|
describe ".count" do
|
117
112
|
it "should return the query for getting the row count" do
|
118
|
-
@query.count.to_s.
|
119
|
-
'SELECT count(Id) FROM table_name'
|
113
|
+
expect(@query.count.to_s).to eq 'SELECT count(Id) FROM table_name'
|
120
114
|
end
|
121
115
|
|
122
116
|
it "should work with a condition" do
|
123
|
-
@query.where("name = 'cool'").count.to_s.
|
124
|
-
"SELECT count(Id) FROM table_name WHERE name = 'cool'"
|
117
|
+
expect(@query.where("name = 'cool'").count.to_s).to eq "SELECT count(Id) FROM table_name WHERE name = 'cool'"
|
125
118
|
end
|
126
119
|
end
|
127
120
|
|
128
121
|
describe '.options' do
|
129
122
|
it 'should add a where if the option has a where condition' do
|
130
|
-
@query.options(where: 'var = 1').to_s.
|
131
|
-
"SELECT Id, name, etc FROM table_name WHERE var = 1"
|
123
|
+
expect(@query.options(where: 'var = 1').to_s).to eq "SELECT Id, name, etc FROM table_name WHERE var = 1"
|
132
124
|
end
|
133
125
|
|
134
126
|
it 'should add a limit if the option has a limit condition' do
|
135
|
-
@query.options(limit: 1).to_s.
|
136
|
-
"SELECT Id, name, etc FROM table_name LIMIT 1"
|
127
|
+
expect(@query.options(limit: 1).to_s).to eq "SELECT Id, name, etc FROM table_name LIMIT 1"
|
137
128
|
end
|
138
129
|
|
139
130
|
it 'should add a order if the option has a order condition' do
|
140
|
-
@query.options(order: 'name desc').to_s.
|
141
|
-
"SELECT Id, name, etc FROM table_name ORDER BY name desc"
|
131
|
+
expect(@query.options(order: 'name desc').to_s).to eq "SELECT Id, name, etc FROM table_name ORDER BY name desc"
|
142
132
|
end
|
143
133
|
|
144
134
|
it 'should work with multiples options' do
|
145
|
-
@query.options(where: 'var = 1', order: 'name desc', limit: 1).to_s.
|
146
|
-
"SELECT Id, name, etc FROM table_name WHERE var = 1 ORDER BY name desc LIMIT 1"
|
135
|
+
expect(@query.options(where: 'var = 1', order: 'name desc', limit: 1).to_s).to eq "SELECT Id, name, etc FROM table_name WHERE var = 1 ORDER BY name desc LIMIT 1"
|
147
136
|
end
|
148
137
|
end
|
149
138
|
end
|
@@ -25,5 +25,13 @@ describe ActiveForce::SObject do
|
|
25
25
|
expect(EnforcedTableName.table_name).to eq('Forced__c')
|
26
26
|
end
|
27
27
|
|
28
|
+
it "doesn't include a namespace" do
|
29
|
+
module Foo
|
30
|
+
class Bar < ActiveForce::SObject
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
expect(Foo::Bar.table_name).to eq('Bar__c')
|
35
|
+
end
|
28
36
|
end
|
29
37
|
end
|
@@ -2,20 +2,18 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe ActiveForce::SObject do
|
4
4
|
let(:sobject_hash) { YAML.load(fixture('sobject/single_sobject_hash')) }
|
5
|
+
let(:client) { double 'Client' }
|
5
6
|
|
6
7
|
before do
|
7
|
-
::
|
8
|
-
end
|
9
|
-
|
10
|
-
after do
|
11
|
-
Object.send :remove_const, 'Client'
|
8
|
+
allow(ActiveForce::SObject).to receive(:sfdc_client).and_return client
|
12
9
|
end
|
13
10
|
|
14
11
|
describe ".new" do
|
15
|
-
|
16
|
-
|
17
|
-
expect(
|
12
|
+
|
13
|
+
it 'should assigns values when are passed by parameters' do
|
14
|
+
expect(Whizbang.new({ text: 'some text' }).text).to eq 'some text'
|
18
15
|
end
|
16
|
+
|
19
17
|
end
|
20
18
|
|
21
19
|
describe ".build" do
|
@@ -41,6 +39,38 @@ describe ActiveForce::SObject do
|
|
41
39
|
expect(Whizbang.attribute_names).to include(name)
|
42
40
|
end
|
43
41
|
end
|
42
|
+
|
43
|
+
it "uses Salesforce API naming conventions by default" do
|
44
|
+
expect(Whizbang.mappings[:estimated_close_date]).to eq 'Estimated_Close_Date__c'
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'having an id' do
|
48
|
+
it 'has one by default' do
|
49
|
+
expect(Territory.new).to respond_to(:id)
|
50
|
+
expect(Territory.mappings[:id]).to eq 'Id'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'can be overridden' do
|
54
|
+
expect(Quota.new).to respond_to(:id)
|
55
|
+
expect(Quota.mappings[:id]).to eq 'Bar_Id__c'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#update' do
|
61
|
+
|
62
|
+
subject do
|
63
|
+
Whizbang.new
|
64
|
+
end
|
65
|
+
|
66
|
+
before do
|
67
|
+
expect(client).to receive(:update!).and_return('id')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'delegates to the Client with create!' do
|
71
|
+
expect(subject.update({ text: 'some text' })).to be_a Whizbang
|
72
|
+
end
|
73
|
+
|
44
74
|
end
|
45
75
|
|
46
76
|
describe '#create' do
|
@@ -50,7 +80,7 @@ describe ActiveForce::SObject do
|
|
50
80
|
end
|
51
81
|
|
52
82
|
before do
|
53
|
-
|
83
|
+
expect(client).to receive(:create!).and_return('id')
|
54
84
|
end
|
55
85
|
|
56
86
|
it 'delegates to the Client with create!' do
|
@@ -64,36 +94,36 @@ describe ActiveForce::SObject do
|
|
64
94
|
|
65
95
|
end
|
66
96
|
|
97
|
+
describe 'self.create' do
|
98
|
+
|
99
|
+
before do
|
100
|
+
expect(client).to receive(:create!).and_return('id')
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should create a new instance' do
|
104
|
+
expect(Whizbang.create({ text: 'some text' })).to be_a Whizbang
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
67
109
|
describe "#count" do
|
68
110
|
let(:count_response){ [Restforce::Mash.new(expr0: 1)] }
|
69
111
|
|
70
112
|
it "responds to count" do
|
71
|
-
Whizbang.
|
113
|
+
expect(Whizbang).to respond_to(:count)
|
72
114
|
end
|
73
115
|
|
74
116
|
it "sends the query to the client" do
|
75
|
-
expect(
|
117
|
+
expect(client).to receive(:query).and_return(count_response)
|
76
118
|
expect(Whizbang.count).to eq(1)
|
77
119
|
end
|
78
120
|
|
79
121
|
end
|
80
122
|
|
81
|
-
# describe "first" do
|
82
|
-
# it "should return the first value" do
|
83
|
-
# binding.pry
|
84
|
-
# expect(Whizbang.first).to eq(1)
|
85
|
-
# end
|
86
|
-
# end
|
87
|
-
|
88
123
|
describe "#find_by" do
|
89
|
-
it "responds to find_by" do
|
90
|
-
Whizbang.should respond_to(:find_by)
|
91
|
-
end
|
92
|
-
|
93
124
|
it "should query the client, with the SFDC field names and correctly enclosed values" do
|
94
|
-
|
125
|
+
expect(client).to receive(:query).with("SELECT #{Whizbang.fields.join ', '} FROM Whizbang__c WHERE Id = 123 AND Text_Label = 'foo' LIMIT 1")
|
95
126
|
Whizbang.find_by id: 123, text: "foo"
|
96
127
|
end
|
97
128
|
end
|
98
|
-
|
99
129
|
end
|
data/spec/active_force_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
data/spec/support/whizbang.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_force
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eloy Espinaco
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2014-08-
|
14
|
+
date: 2014-08-26 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: active_attr
|
@@ -170,3 +170,4 @@ test_files:
|
|
170
170
|
- spec/spec_helper.rb
|
171
171
|
- spec/support/fixture_helpers.rb
|
172
172
|
- spec/support/whizbang.rb
|
173
|
+
has_rdoc:
|