external_fields 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7f07e8a7db6679bd7137bc5b612118d5d7554738
4
+ data.tar.gz: 9591ced4076f386180722d103d6177e46ea9f6f0
5
+ SHA512:
6
+ metadata.gz: 47c6d1ceacace126d600488a85b980ba7c466d32ef80e7b15b147015410134ae8b4a41175cc1ff911785e15499805cbaef07f89a5d38eda5a9694e142fa57fb6
7
+ data.tar.gz: 650583bada54722659ce56b4ac884e1b5fa460116263c32be4588e6ab31057c1e1480db31ca4fbabf81689503799da58f7d08f09d42af621ebe4fe11499e080a
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.gem
data/.overcommit.yml ADDED
@@ -0,0 +1,60 @@
1
+ CommitMsg:
2
+ CapitalizedSubject:
3
+ enabled: true
4
+ HardTabs:
5
+ enabled: true
6
+ RussianNovel:
7
+ enabled: true
8
+ SingleLineSubject:
9
+ enabled: true
10
+ TextWidth:
11
+ enabled: true
12
+ TrailingPeriod:
13
+ enabled: true
14
+ PreCommit:
15
+ AuthorEmail:
16
+ enabled: true
17
+ AuthorName:
18
+ enabled: true
19
+ Brakeman: # Performs static code security checking.
20
+ enabled: false
21
+ BrokenSymlinks:
22
+ enabled: true
23
+ BundleCheck:
24
+ enabled: true
25
+ CssLint:
26
+ enabled: true
27
+ HamlLint:
28
+ enabled: true
29
+ HardTabs:
30
+ enabled: true
31
+ HtmlTidy: # Uses the `tidy` executable (installed on OS X by default).
32
+ enabled: true
33
+ ImageOptim:
34
+ enabled: true
35
+ Jscs: # Checks for JavaScript style.
36
+ enabled: true
37
+ JsHint: # Checks for JavaScript best practices.
38
+ enabled: true
39
+ JsonSyntax:
40
+ enabled: true
41
+ LocalPathsInGemfile:
42
+ enabled: true
43
+ MergeConflicts:
44
+ enabled: true
45
+ PryBinding:
46
+ enabled: true
47
+ Reek:
48
+ enabled: false
49
+ RuboCop:
50
+ enabled: true
51
+ problem_on_unmodified_line: warn
52
+ ScssLint:
53
+ enabled: true
54
+ TrailingWhitespace:
55
+ enabled: true
56
+ TravisLint: # Checks Travis CI configurations. We use Travis for our open-
57
+ # source repositories.
58
+ enabled: true
59
+ YamlSyntax:
60
+ enabled: true
data/.rubocop.yml ADDED
@@ -0,0 +1,271 @@
1
+ require:
2
+ - rubocop/rspec/focused
3
+
4
+ # This (http://c2.com/cgi/wiki?AbcMetric) is super obnoxious
5
+ AbcSize:
6
+ Enabled: false
7
+
8
+ AccessorMethodName:
9
+ Enabled: false
10
+
11
+ Alias:
12
+ Enabled: false
13
+
14
+ AllCops:
15
+ Exclude:
16
+ - "vendor/**/*"
17
+ - "spec/dummy/**/*"
18
+ - "db/schema.rb"
19
+ - "db/migrate/**/*"
20
+ RunRailsCops: true
21
+
22
+ AmbiguousOperator:
23
+ Enabled: false
24
+
25
+ AmbiguousRegexpLiteral:
26
+ Enabled: false
27
+
28
+ ArrayJoin:
29
+ Enabled: false
30
+
31
+ AsciiComments:
32
+ Enabled: false
33
+
34
+ AsciiIdentifiers:
35
+ Enabled: false
36
+
37
+ AssignmentInCondition:
38
+ Enabled: true
39
+
40
+ Attr:
41
+ Enabled: false
42
+
43
+ BlockNesting:
44
+ Enabled: false
45
+
46
+ BracesAroundHashParameters:
47
+ Enabled: false
48
+
49
+ CaseEquality:
50
+ Enabled: false
51
+
52
+ CharacterLiteral:
53
+ Enabled: false
54
+
55
+ ClassLength:
56
+ Enabled: false
57
+
58
+ ClassVars:
59
+ Enabled: false
60
+
61
+ CollectionMethods:
62
+ PreferredMethods:
63
+ find: detect
64
+ reduce: inject
65
+ collect: map
66
+ find_all: select
67
+
68
+ ColonMethodCall:
69
+ Enabled: false
70
+
71
+ CommentAnnotation:
72
+ Enabled: false
73
+
74
+ ConditionPosition:
75
+ Enabled: false
76
+
77
+ CyclomaticComplexity:
78
+ Enabled: false
79
+
80
+ Delegate:
81
+ Enabled: false
82
+
83
+ DeprecatedClassMethods:
84
+ Enabled: false
85
+
86
+ DeprecatedHashMethods:
87
+ Enabled: false
88
+
89
+ Documentation:
90
+ Enabled: false
91
+
92
+ DotPosition:
93
+ EnforcedStyle: trailing
94
+
95
+ DoubleNegation:
96
+ Enabled: false
97
+
98
+ ElseLayout:
99
+ Enabled: false
100
+
101
+ EmptyLiteral:
102
+ Enabled: false
103
+
104
+ Encoding:
105
+ Enabled: false
106
+
107
+ EvenOdd:
108
+ Enabled: false
109
+
110
+ FileName:
111
+ Enabled: false
112
+
113
+ FlipFlop:
114
+ Enabled: false
115
+
116
+ FormatString:
117
+ Enabled: false
118
+
119
+ GlobalVars:
120
+ Enabled: false
121
+
122
+ GuardClause:
123
+ Enabled: false
124
+
125
+ HandleExceptions:
126
+ Enabled: false
127
+
128
+ IfUnlessModifier:
129
+ Enabled: false
130
+
131
+ IfWithSemicolon:
132
+ Enabled: false
133
+
134
+ InvalidCharacterLiteral:
135
+ Enabled: false
136
+
137
+ Lambda:
138
+ Enabled: false
139
+
140
+ LambdaCall:
141
+ Enabled: false
142
+
143
+ LineEndConcatenation:
144
+ Enabled: false
145
+
146
+ LineLength:
147
+ Max: 80
148
+
149
+ LiteralInCondition:
150
+ Enabled: false
151
+
152
+ LiteralInInterpolation:
153
+ Enabled: false
154
+
155
+ Loop:
156
+ Enabled: false
157
+
158
+ MethodLength:
159
+ Enabled: false
160
+
161
+ ModuleFunction:
162
+ Enabled: false
163
+
164
+ NegatedIf:
165
+ Enabled: false
166
+
167
+ NegatedWhile:
168
+ Enabled: false
169
+
170
+ Next:
171
+ Enabled: false
172
+
173
+ NilComparison:
174
+ Enabled: false
175
+
176
+ Not:
177
+ Enabled: false
178
+
179
+ NumericLiterals:
180
+ Enabled: false
181
+
182
+ OneLineConditional:
183
+ Enabled: false
184
+
185
+ OpMethod:
186
+ Enabled: false
187
+
188
+ ParameterLists:
189
+ Enabled: false
190
+
191
+ ParenthesesAsGroupedExpression:
192
+ Enabled: false
193
+
194
+ PercentLiteralDelimiters:
195
+ PreferredDelimiters:
196
+ '%': '{}'
197
+
198
+ PerceivedComplexity:
199
+ Enabled: false
200
+
201
+ PerlBackrefs:
202
+ Enabled: false
203
+
204
+ PredicateName:
205
+ Enabled: false
206
+
207
+ Proc:
208
+ Enabled: false
209
+
210
+ RaiseArgs:
211
+ Enabled: false
212
+
213
+ RedundantReturn:
214
+ AllowMultipleReturnValues: true
215
+
216
+ RegexpLiteral:
217
+ Enabled: false
218
+
219
+ RequireParentheses:
220
+ Enabled: false
221
+
222
+ Rspec/Focused:
223
+ Enabled: true
224
+
225
+ SelfAssignment:
226
+ Enabled: false
227
+
228
+ SignalException:
229
+ EnforcedStyle: only_raise
230
+
231
+ SingleLineBlockParams:
232
+ Enabled: false
233
+
234
+ SingleLineMethods:
235
+ Enabled: false
236
+
237
+ SpecialGlobalVars:
238
+ Enabled: false
239
+
240
+ StringLiterals:
241
+ EnforcedStyle: double_quotes
242
+
243
+ Style/MultilineBlockChain:
244
+ Enabled: false
245
+
246
+ VariableInterpolation:
247
+ Enabled: false
248
+
249
+ TrailingComma:
250
+ Enabled: false
251
+
252
+ TrivialAccessors:
253
+ Enabled: false
254
+
255
+ UnderscorePrefixedVariableName:
256
+ Enabled: false
257
+
258
+ VariableInterpolation:
259
+ Enabled: false
260
+
261
+ Void:
262
+ Enabled: false
263
+
264
+ WhenThen:
265
+ Enabled: false
266
+
267
+ WhileUntilModifier:
268
+ Enabled: false
269
+
270
+ WordArray:
271
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.1
4
+ script: bundle exec rspec
5
+ addons:
6
+ code_climate:
7
+ repo_token: 9f025c501f5daf9ffc6712005e4cda18ce4f6afe76c2c0913889712cefb3679e
8
+ notifications:
9
+ email: false
10
+ hipchat:
11
+ rooms:
12
+ secure: c6XVH78Isrp/TvZsQaq2Ne442rLoUU5FX4N6PgF8jdbMIiPN5dEyURH1LgBop5grv2ZY8BwZeVjNvKVlr8V9wDoER6AV81MclV398qOiIy020dS8ahgpj7F7EO/hKU3iQX4d+3r3a5oeeWjDXdN4uPbeWR5uLXEsXDtX3HUZGxc1p/fT8xUSQufb+kZXccrYV2ryWIa7bQxWlpfAnTm/VQxl3tf5riK7vjq1TkwxvNl4Rv5TjkPFJkryyEcDtutX1jWF8O/nsxzejG604pfyZHcoDjl5erIatalHDwOxr7H1u0XYVpnldiv/L37TGkZaMWuRnCraWn6GDdmqWrpRWYqQfanpdNq9iNB8lWpsPDfnMgLQAbDnSobeeKkkQAeY0lgZjDwcP8AySjEGX/BhdIcYgs6l3C6JR3lj1P47w0KU9YgOxrRf32RGfVRfbT9cz/xqalPjVpJPOmdEoG4vC9tWZTaTBHNnmfJwrcuqnbCLh3mufVvjQD8LDo53xzKJqDguR+j7G0pKfYrwRyRbc1fwBeiVhQwmwtS8u/Swr8ImHN1r50Ma4FId+dBRkstqunfzHjchv/Om96KVPp8rL1sTMHyZvobre8OA4ovjxgQfTFIXholNtOH4Ege/ol9KxF+Sg1fBeELT8c2Jw8Hp46WduyrIcFkRBgNnSqcKnD8=
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in external_fields.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Panorama Education
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,152 @@
1
+ [![Code Climate](https://codeclimate.com/github/panorama-ed/rails_external_fields/badges/gpa.svg)](https://codeclimate.com/github/panorama-ed/rails_external_fields) [![Test Coverage](https://codeclimate.com/github/panorama-ed/rails_external_fields/badges/coverage.svg)](https://codeclimate.com/github/panorama-ed/rails_external_fields) [![Build Status](https://travis-ci.org/panorama-ed/rails_external_fields.svg)](https://travis-ci.org/panorama-ed/rails_external_fields) [![Inline docs](http://inch-ci.org/github/panorama-ed/rails_external_fields.png)](http://inch-ci.org/github/panorama-ed/rails_external_fields) [![Gem Version](https://badge.fury.io/rb/rails_external_fields.svg)](http://badge.fury.io/rb/rails_external_fields)
2
+
3
+ # ExternalFields
4
+ Create the illusion that an object has specific attributes when those attributes
5
+ actually belong to an associated object.
6
+
7
+ This is particularly useful for different classes within a single-
8
+ table inheritance table to have access to separate fields in class-specific
9
+ associations.
10
+
11
+ ## Installation
12
+ Add this line to your application's Gemfile:
13
+
14
+ ````
15
+ gem "external_fields"
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ ```
21
+ $ bundle
22
+ ```
23
+
24
+ Or install it yourself as:
25
+
26
+ ```
27
+ $ gem install external_fields
28
+ ```
29
+
30
+ ## Usage
31
+ Include `ExternalFields` and define the external fields using the `external_field` method. For example, if `grade_level`, `age` and `credits` are defined in another class `StudentData` and you want to access them in `Student` you could do:
32
+
33
+ ```ruby
34
+ require "active_record"
35
+ require "active_support"
36
+
37
+ require "external_fields"
38
+
39
+ class Student < ActiveRecord::Base
40
+ include ExternalFields
41
+
42
+ has_one :data,
43
+ class_name: StudentData
44
+
45
+ external_field :grade_level, # External attribute 1
46
+ :age, # External attribute 2
47
+ :credits, # External attribute 3
48
+ :data, # Name of the association
49
+ class_name: "StudentData" # Class name of association
50
+ end
51
+ ```
52
+
53
+ where the external fields are defined in another associated class:
54
+
55
+ ```ruby
56
+ class StudentData < ActiveRecord::Base
57
+ attr_accessor :grade_level, :age, :credits
58
+ end
59
+ ```
60
+
61
+ Now you can directly call the accessors on the `Student` objects:
62
+
63
+ ```ruby
64
+ > s = Student.create!
65
+ > s.age
66
+ => nil
67
+
68
+ > s.age = 10
69
+ > s.age
70
+ => 10
71
+
72
+ > s.grade_level = 4
73
+ > s.grade_level
74
+ => 4
75
+ ```
76
+
77
+ ### Overriding default behavior using `underscored` accessors
78
+ You can also add underscored accessors using the `underscore` flag
79
+
80
+ ```ruby
81
+ ...
82
+ external_field :grade_level, # External attribute 1
83
+ :age, # External attribute 2
84
+ :credits, # External attribute 3
85
+ :data, # Name of the association
86
+ class_name: "StudentData" # Class name of association
87
+ underscore: true # Flag for underscored accessors
88
+ ...
89
+ ```
90
+
91
+ This will allow you to use the external fields using underscored methods:
92
+ ```ruby
93
+ s = Student.create!
94
+ s._age
95
+ s._grade_level
96
+ ```
97
+
98
+ This approach lets you override the default behavior cleanly. For example,
99
+ you could override the grade level using this method:
100
+
101
+ ```ruby
102
+ def grade_level
103
+ if _grade_level == 0
104
+ "Kindergarten"
105
+ else
106
+ _grade_level
107
+ end
108
+ end
109
+ ```
110
+
111
+ ### Accessing the original association
112
+
113
+ In some instances it's helpful to be able to use the original association
114
+ without building an object on access. For instance, you might want to have a
115
+ validation inspect a value without creating a new object on each save. In that
116
+ case, you can use the `use_original` flag on the association like so:
117
+
118
+ ```ruby
119
+ validate :kindergarten_students_have_names
120
+
121
+ def kindergarten_students_have_names
122
+ data_obj = data(use_original: true)
123
+
124
+ if data_obj && grade_level == "Kindergarten" && name.blank?
125
+ # Note that `name` is an attribute on `Student` but `grade_level`
126
+ # is accessed through the `data` association as defined earlier
127
+ # in the README.
128
+ errors.add(:name, "must be present for kindergarten students")
129
+ end
130
+ end
131
+ ```
132
+
133
+ ## Documentation
134
+
135
+ We have documentation on [RubyDoc](http://www.rubydoc.info/github/panorama-ed/rails_external_fields/master).
136
+
137
+ ## Contributing
138
+
139
+ 1. Fork it (https://github.com/panorama-ed/rails_external_fields/fork)
140
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
141
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
142
+ 4. Push to the branch (`git push origin my-new-feature`)
143
+ 5. Create a new Pull Request
144
+
145
+ **Make sure your changes have appropriate tests (`bundle exec rspec`)
146
+ and conform to the Rubocop style specified.** We use
147
+ [overcommit](https://github.com/causes/overcommit) to enforce good code.
148
+
149
+ ## License
150
+
151
+ `ExternalFields` is released under the
152
+ [MIT License](https://github.com/panorama-ed/rails_external_fields/blob/master/LICENSE).
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "external_fields/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "external_fields"
8
+ spec.version = ExternalFields::VERSION
9
+ spec.authors = ["Sagar Jauhari"]
10
+ spec.email = ["sagarjauhari@gmail.com"]
11
+ spec.summary = "Access attributes from an associated model."
12
+ spec.description = "This concern maintains the illusion that a given "\
13
+ "object has specified attributes, when those "\
14
+ "attributes are in fact attached to an associated "\
15
+ "object. This is particularly useful for different "\
16
+ "classes within a single-table inheritance table to "\
17
+ "have access to separate fields in class-specific "\
18
+ "associations."
19
+
20
+ spec.homepage = "https://github.com/panorama-ed/rails-external-fields"
21
+ spec.license = "MIT"
22
+
23
+ spec.files = `git ls-files -z`.split("\x0")
24
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
25
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_dependency "activerecord", "~> 4.0"
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.7"
31
+ spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4"
32
+ spec.add_development_dependency "overcommit", "~> 0.23"
33
+ spec.add_development_dependency "rspec", "~> 3.2"
34
+ spec.add_development_dependency "rspec-rails", "~> 3.2"
35
+ spec.add_development_dependency "rubocop", "~> 0.29"
36
+ spec.add_development_dependency "rubocop-rspec-focused", "~> 0.0"
37
+ spec.add_development_dependency "temping", "~> 3.2"
38
+ spec.add_development_dependency "sqlite3", "~> 1.3"
39
+ end
@@ -0,0 +1,3 @@
1
+ module ExternalFields
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,87 @@
1
+ require "external_fields/version"
2
+
3
+ # This concern maintains the illusion that a given object has specified
4
+ # attributes, when those attributes are in fact attached to an associated
5
+ # object. This is particularly useful for different classes within a single-
6
+ # table inheritance table to have access to separate fields in class-specific
7
+ # associations.
8
+
9
+ module ExternalFields
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ class_attribute :_external_field_associations
14
+
15
+ # Provides a getter and setter for the given attribute on the associated
16
+ # object. We provide either normal or underscored getters and setters, the
17
+ # latter allowing the defining class to use alias_method to override
18
+ # behavior while still accessing these underlying implementations.
19
+ #
20
+ # @param attrs [Array<Symbol>] list of external fields
21
+ # @param assoc [Symbol] name of the association
22
+ # @param class_name [String] name of the associated class
23
+ # @param underscore [Boolean] underscored accessor created if true
24
+ def self.external_field(*attrs, assoc, class_name: nil, underscore: false)
25
+ self._external_field_associations ||= []
26
+
27
+ attrs.each do |attr|
28
+ # Store the original association method for use in the overwritten one.
29
+ original_method = instance_method(assoc)
30
+
31
+ # First, we define an accessor for the associated object.
32
+ # Note we ensure that we only define the accessor once. Further, if
33
+ # `use_original` is true, we use the original Rails association
34
+ # accessor, which will not build a new object. Otherwise, we build a new
35
+ # object if one does not exist already.
36
+ unless self._external_field_associations.include? assoc
37
+ define_method assoc do |use_original: false|
38
+ if use_original
39
+ # Call original overwritten method
40
+ original_method.bind(self).call
41
+ else
42
+ # Try calling the original method to see if we get a result.
43
+ existing_value = original_method.bind(self).call
44
+
45
+ # Use existing value if one is there.
46
+ if existing_value
47
+ existing_value
48
+ else # Otherwise, build a new object.
49
+ # Find the class of the object we need to build.
50
+ klass = class_name.try(:constantize) ||
51
+ self.class.reflect_on_association(assoc).klass
52
+
53
+ send("#{assoc}=", klass.new)
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ # Now, define the getters for the specific attribute.
60
+ define_method(underscore ? "_#{attr}" : attr) do
61
+ send(assoc).try(attr)
62
+ end
63
+
64
+ # Now, define the setters for the specific attribute.
65
+ define_method(underscore ? "_#{attr}=" : "#{attr}=") do |new_attr|
66
+ send(assoc).send("#{attr}=", new_attr)
67
+ end
68
+
69
+ # Add the association name to the set of external field associations.
70
+ # This allows other parts of the codebase to quickly see all of the
71
+ # associations a class has that store external fields. This array stores
72
+ # association name symbols, like: [:address, :extra_data]
73
+ # Note that a Set could be used here but an Array was chosen for
74
+ # familiarity since the size of the array will be relatively small.
75
+ unless self._external_field_associations.include? assoc
76
+ # We need to duplicate the array because a subclass of a model with
77
+ # this mixin would otherwise modify its parent class' array, since the
78
+ # << operator works in-place.
79
+ self._external_field_associations =
80
+ self._external_field_associations.dup
81
+
82
+ self._external_field_associations << assoc
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,90 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe ExternalFields do
4
+ describe ".external_fields" do
5
+ describe "the association" do
6
+ Temping.create :test_class do
7
+ with_columns do |t|
8
+ t.string :name
9
+ end
10
+
11
+ include ExternalFields
12
+
13
+ has_one :assoc,
14
+ class_name: "AssociationTestClass"
15
+
16
+ external_field :ext_field_1,
17
+ :assoc,
18
+ class_name: "AssociationTestClass"
19
+
20
+ external_field :ext_field_2,
21
+ :assoc,
22
+ class_name: "AssociationTestClass",
23
+ underscore: true
24
+ end
25
+
26
+ Temping.create :association_test_class do
27
+ with_columns do |t|
28
+ t.integer :test_class_id
29
+ t.string :ext_field_1
30
+ t.string :ext_field_2
31
+ end
32
+
33
+ belongs_to :test_class
34
+ end
35
+
36
+ # Clean up after each test. This is a lot lighter for these few tests than
37
+ # trying to wrangle with RSpec-Rails to get transactional tests to work.
38
+ after :each do
39
+ TestClass.delete_all
40
+ AssociationTestClass.delete_all
41
+ end
42
+
43
+ it "should be built on first access" do
44
+ e = TestClass.create!(name: "Hello")
45
+
46
+ expect(AssociationTestClass.count).to eq(0)
47
+ expect(e.assoc.class).to eq(AssociationTestClass)
48
+ end
49
+
50
+ it "should be saved when the model is saved" do
51
+ e = TestClass.create!(name: "Hello")
52
+ expect(AssociationTestClass.count).to eq(0)
53
+ expect(e.assoc.class).to eq(AssociationTestClass)
54
+ e.save!
55
+ expect(AssociationTestClass.count).to eq(1)
56
+ end
57
+
58
+ it "should not be created or saved if unused" do
59
+ e = TestClass.create!
60
+ e.name = "TEST"
61
+ e.save!
62
+ expect(AssociationTestClass.count).to eq(0)
63
+ end
64
+
65
+ it "should be created if used" do
66
+ e = TestClass.create!(name: "Hello", ext_field_1: "Field1")
67
+
68
+ expect(AssociationTestClass.count).to eq(1)
69
+ expect(e.ext_field_1).to eq "Field1"
70
+ end
71
+
72
+ context "when underscore flag is true" do
73
+ it "should provide underscored methods" do
74
+ e = TestClass.create!(_ext_field_2: "_Field2")
75
+
76
+ expect(AssociationTestClass.count).to eq(1)
77
+ expect(e._ext_field_2).to eq "_Field2"
78
+ end
79
+ end
80
+
81
+ it "should provide an accessor that does not build a new object" do
82
+ e = TestClass.new(name: "Hello")
83
+
84
+ e.assoc(use_original: true) # Access without creating
85
+ e.save!
86
+ expect(AssociationTestClass.count).to eq 0
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,48 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
3
+
4
+ # Connect to an in-memory database for ActiveRecord tests.
5
+ require "temping"
6
+ ActiveRecord::Base.
7
+ establish_connection(adapter: "sqlite3", database: ":memory:")
8
+
9
+ require "external_fields"
10
+
11
+ RSpec.configure do |config|
12
+ # These two settings work together to allow you to limit a spec run
13
+ # to individual examples or groups you care about by tagging them with
14
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
15
+ # get run.
16
+ config.filter_run :focus
17
+ config.run_all_when_everything_filtered = true
18
+
19
+ # Limits the available syntax to the non-monkey patched syntax that is
20
+ # recommended.
21
+ # For more details, see:
22
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
23
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
24
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
25
+ config.disable_monkey_patching!
26
+
27
+ # Many RSpec users commonly either run the entire suite or an individual
28
+ # file, and it's useful to allow more verbose output when running an
29
+ # individual spec file.
30
+ if config.files_to_run.one?
31
+ # Use the documentation formatter for detailed output,
32
+ # unless a formatter has already been configured
33
+ # (e.g. via a command-line flag).
34
+ config.default_formatter = "doc"
35
+ end
36
+
37
+ # Run specs in random order to surface order dependencies. If you find an
38
+ # order dependency and want to debug it, you can fix the order by providing
39
+ # the seed, which is printed after each run.
40
+ # --seed 1234
41
+ config.order = :random
42
+
43
+ # Seed global randomization in this process using the `--seed` CLI option.
44
+ # Setting this allows you to use `--seed` to deterministically reproduce
45
+ # test failures related to randomization by passing the same `--seed` value
46
+ # as the one that triggered the failure.
47
+ Kernel.srand config.seed
48
+ end
metadata ADDED
@@ -0,0 +1,202 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: external_fields
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sagar Jauhari
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.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.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: codeclimate-test-reporter
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: overcommit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.23'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.23'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.29'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.29'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rspec-focused
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: temping
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.2'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.2'
139
+ - !ruby/object:Gem::Dependency
140
+ name: sqlite3
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1.3'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1.3'
153
+ description: This concern maintains the illusion that a given object has specified
154
+ attributes, when those attributes are in fact attached to an associated object.
155
+ This is particularly useful for different classes within a single-table inheritance
156
+ table to have access to separate fields in class-specific associations.
157
+ email:
158
+ - sagarjauhari@gmail.com
159
+ executables: []
160
+ extensions: []
161
+ extra_rdoc_files: []
162
+ files:
163
+ - ".gitignore"
164
+ - ".overcommit.yml"
165
+ - ".rubocop.yml"
166
+ - ".travis.yml"
167
+ - Gemfile
168
+ - LICENSE
169
+ - README.md
170
+ - external_fields.gemspec
171
+ - lib/external_fields.rb
172
+ - lib/external_fields/version.rb
173
+ - spec/external_fields_spec.rb
174
+ - spec/spec_helper.rb
175
+ homepage: https://github.com/panorama-ed/rails-external-fields
176
+ licenses:
177
+ - MIT
178
+ metadata: {}
179
+ post_install_message:
180
+ rdoc_options: []
181
+ require_paths:
182
+ - lib
183
+ required_ruby_version: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ required_rubygems_version: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: '0'
193
+ requirements: []
194
+ rubyforge_project:
195
+ rubygems_version: 2.4.8
196
+ signing_key:
197
+ specification_version: 4
198
+ summary: Access attributes from an associated model.
199
+ test_files:
200
+ - spec/external_fields_spec.rb
201
+ - spec/spec_helper.rb
202
+ has_rdoc: