├── .codeclimate.yml ├── .gitignore ├── .rubocop.yml ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── Gemfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── lib ├── poly_belongs_to.rb └── poly_belongs_to │ ├── core.rb │ ├── dup.rb │ ├── faked_collection.rb │ ├── pbt.rb │ ├── singleton_set.rb │ ├── sorted_reflection_decorator.rb │ └── version.rb ├── poly_belongs_to.gemspec └── test ├── core_test.rb ├── dummy ├── Rakefile ├── app │ ├── controllers │ │ ├── application_controller.rb │ │ └── concerns │ │ │ └── .keep │ ├── helpers │ │ └── application_helper.rb │ ├── mailers │ │ └── .keep │ ├── models │ │ ├── .keep │ │ ├── address.rb │ │ ├── address_book.rb │ │ ├── alpha.rb │ │ ├── assembly.rb │ │ ├── beta.rb │ │ ├── big_company.rb │ │ ├── capa.rb │ │ ├── car.rb │ │ ├── coffee.rb │ │ ├── concerns │ │ │ └── .keep │ │ ├── contact.rb │ │ ├── delta.rb │ │ ├── event.rb │ │ ├── geo_location.rb │ │ ├── hmt_assembly.rb │ │ ├── hmt_part.rb │ │ ├── manifest.rb │ │ ├── part.rb │ │ ├── phone.rb │ │ ├── photo.rb │ │ ├── profile.rb │ │ ├── squishy.rb │ │ ├── ssn.rb │ │ ├── tag.rb │ │ ├── tire.rb │ │ ├── user.rb │ │ └── work_order.rb │ └── views │ │ └── layouts │ │ └── application.html.erb ├── bin │ ├── bundle │ ├── rails │ ├── rake │ └── setup ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── assets.rb │ │ ├── backtrace_silencers.rb │ │ ├── cookies_serializer.rb │ │ ├── filter_parameter_logging.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ ├── session_store.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ └── en.yml │ ├── routes.rb │ └── secrets.yml ├── db │ ├── migrate │ │ ├── 20150211224139_create_users.rb │ │ ├── 20150211224157_create_tags.rb │ │ ├── 20150211224225_create_phones.rb │ │ ├── 20150216092218_create_addresses.rb │ │ ├── 20150216092338_create_profiles.rb │ │ ├── 20150216092411_create_photos.rb │ │ ├── 20150216092449_create_contacts.rb │ │ ├── 20150216092519_create_ssns.rb │ │ ├── 20150220213422_create_geo_locations.rb │ │ ├── 20150220230146_create_squishies.rb │ │ ├── 20150301100658_create_tires.rb │ │ ├── 20150301100722_create_cars.rb │ │ ├── 20150322233720_create_alphas.rb │ │ ├── 20150322233733_create_beta.rb │ │ ├── 20150322233743_create_capas.rb │ │ ├── 20150322233755_create_delta.rb │ │ ├── 20150511161648_create_coffees.rb │ │ ├── 20160120224015_add_contactable_to_contacts.rb │ │ ├── 20160120231645_create_address_books.rb │ │ ├── 20161209115003_create_events.rb │ │ ├── 20161209115212_create_work_orders.rb │ │ ├── 20161210074545_create_big_companies.rb │ │ ├── 20161210074616_add_big_company_id_to_work_order.rb │ │ ├── 20161210145334_create_assemblies.rb │ │ ├── 20161210145355_create_parts.rb │ │ ├── 20161210145757_create_assembly_part_join_table.rb │ │ ├── 20161210150330_create_hmt_assemblies.rb │ │ └── 20161210150343_create_hmt_parts.rb │ └── schema.rb ├── lib │ └── assets │ │ └── .keep ├── log │ └── .keep ├── public │ └── favicon.ico └── test │ ├── fixtures │ ├── assemblies.yml │ ├── big_companies.yml │ ├── coffees.yml │ ├── events.yml │ ├── hmt_assemblies.yml │ ├── hmt_parts.yml │ ├── parts.yml │ └── work_orders.yml │ └── models │ ├── address_book_test.rb │ ├── assembly_test.rb │ ├── big_company_test.rb │ ├── coffee_test.rb │ ├── event_test.rb │ ├── hmt_assembly_test.rb │ ├── hmt_part_test.rb │ ├── part_test.rb │ └── work_order_test.rb ├── dup_test.rb ├── faked_collection_test.rb ├── fixtures ├── address_books.yml ├── addresses.yml ├── cars.yml ├── contacts.yml ├── geo_locations.yml ├── phones.yml ├── photos.yml ├── profiles.yml ├── squishies.yml ├── ssns.yml ├── tags.yml ├── tires.yml └── users.yml ├── major_version_changes_test.rb ├── pbt_test.rb ├── singleton_set_test.rb └── test_helper.rb /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | duplication: 4 | enabled: true 5 | config: 6 | languages: 7 | - ruby 8 | rubocop: 9 | enabled: true 10 | ratings: 11 | paths: 12 | - "**.rb" 13 | exclude_paths: 14 | - test/ 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .bundle/ 3 | .ruby-version 4 | *.gem 5 | *.swp 6 | Gemfile.lock 7 | log/*.log 8 | pkg/ 9 | /doc 10 | .yardoc 11 | test/dummy/db/*.sqlite3 12 | test/dummy/db/*.sqlite3-journal 13 | test/dummy/log/*.log 14 | test/dummy/tmp/ 15 | test/dummy/.sass-cache 16 | coverage 17 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - 'test/dummy/**/*' 4 | DisabledByDefault: true 5 | 6 | #################### Lint ################################ 7 | 8 | Lint/AmbiguousOperator: 9 | Description: >- 10 | Checks for ambiguous operators in the first argument of a 11 | method invocation without parentheses. 12 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-as-args' 13 | Enabled: true 14 | 15 | Lint/AmbiguousRegexpLiteral: 16 | Description: >- 17 | Checks for ambiguous regexp literals in the first argument of 18 | a method invocation without parenthesis. 19 | Enabled: true 20 | 21 | Lint/AssignmentInCondition: 22 | Description: "Don't use assignment in conditions." 23 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#safe-assignment-in-condition' 24 | Enabled: true 25 | 26 | Lint/BlockAlignment: 27 | Description: 'Align block ends correctly.' 28 | Enabled: true 29 | 30 | Lint/CircularArgumentReference: 31 | Description: "Don't refer to the keyword argument in the default value." 32 | Enabled: true 33 | 34 | Lint/ConditionPosition: 35 | Description: >- 36 | Checks for condition placed in a confusing position relative to 37 | the keyword. 38 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#same-line-condition' 39 | Enabled: true 40 | 41 | Lint/Debugger: 42 | Description: 'Check for debugger calls.' 43 | Enabled: true 44 | 45 | Lint/DefEndAlignment: 46 | Description: 'Align ends corresponding to defs correctly.' 47 | Enabled: true 48 | 49 | Lint/DeprecatedClassMethods: 50 | Description: 'Check for deprecated class method calls.' 51 | Enabled: true 52 | 53 | Lint/DuplicateMethods: 54 | Description: 'Check for duplicate methods calls.' 55 | Enabled: true 56 | 57 | Lint/EachWithObjectArgument: 58 | Description: 'Check for immutable argument given to each_with_object.' 59 | Enabled: true 60 | 61 | Lint/ElseLayout: 62 | Description: 'Check for odd code arrangement in an else block.' 63 | Enabled: true 64 | 65 | Lint/EmptyEnsure: 66 | Description: 'Checks for empty ensure block.' 67 | Enabled: true 68 | 69 | Lint/EmptyInterpolation: 70 | Description: 'Checks for empty string interpolation.' 71 | Enabled: true 72 | 73 | Lint/EndAlignment: 74 | Description: 'Align ends correctly.' 75 | Enabled: true 76 | 77 | Lint/EndInMethod: 78 | Description: 'END blocks should not be placed inside method definitions.' 79 | Enabled: true 80 | 81 | Lint/EnsureReturn: 82 | Description: 'Do not use return in an ensure block.' 83 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-return-ensure' 84 | Enabled: true 85 | 86 | Security/Eval: 87 | Description: 'The use of eval represents a serious security risk.' 88 | Enabled: true 89 | 90 | Lint/FormatParameterMismatch: 91 | Description: 'The number of parameters to format/sprint must match the fields.' 92 | Enabled: true 93 | 94 | Lint/HandleExceptions: 95 | Description: "Don't suppress exception." 96 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions' 97 | Enabled: true 98 | 99 | Lint/InvalidCharacterLiteral: 100 | Description: >- 101 | Checks for invalid character literals with a non-escaped 102 | whitespace character. 103 | Enabled: true 104 | 105 | Lint/LiteralInCondition: 106 | Description: 'Checks of literals used in conditions.' 107 | Enabled: true 108 | 109 | Lint/LiteralInInterpolation: 110 | Description: 'Checks for literals used in interpolation.' 111 | Enabled: true 112 | 113 | Lint/Loop: 114 | Description: >- 115 | Use Kernel#loop with break rather than begin/end/until or 116 | begin/end/while for post-loop tests. 117 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#loop-with-break' 118 | Enabled: true 119 | 120 | Lint/NestedMethodDefinition: 121 | Description: 'Do not use nested method definitions.' 122 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-methods' 123 | Enabled: true 124 | 125 | Lint/NonLocalExitFromIterator: 126 | Description: 'Do not use return in iterator to cause non-local exit.' 127 | Enabled: true 128 | 129 | Lint/ParenthesesAsGroupedExpression: 130 | Description: >- 131 | Checks for method calls with a space before the opening 132 | parenthesis. 133 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces' 134 | Enabled: true 135 | 136 | Lint/RequireParentheses: 137 | Description: >- 138 | Use parentheses in the method call to avoid confusion 139 | about precedence. 140 | Enabled: true 141 | 142 | Lint/RescueException: 143 | Description: 'Avoid rescuing the Exception class.' 144 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-blind-rescues' 145 | Enabled: true 146 | 147 | Lint/ShadowingOuterLocalVariable: 148 | Description: >- 149 | Do not use the same name as outer local variable 150 | for block arguments or block local variables. 151 | Enabled: true 152 | 153 | Lint/StringConversionInInterpolation: 154 | Description: 'Checks for Object#to_s usage in string interpolation.' 155 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-to-s' 156 | Enabled: true 157 | 158 | Lint/UnderscorePrefixedVariableName: 159 | Description: 'Do not use prefix `_` for a variable that is used.' 160 | Enabled: true 161 | 162 | Lint/UnneededDisable: 163 | Description: >- 164 | Checks for rubocop:disable comments that can be removed. 165 | Note: this cop is not disabled when disabling all cops. 166 | It must be explicitly disabled. 167 | Enabled: true 168 | 169 | Lint/UnusedBlockArgument: 170 | Description: 'Checks for unused block arguments.' 171 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars' 172 | Enabled: true 173 | 174 | Lint/UnusedMethodArgument: 175 | Description: 'Checks for unused method arguments.' 176 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars' 177 | Enabled: true 178 | 179 | Lint/UnreachableCode: 180 | Description: 'Unreachable code.' 181 | Enabled: true 182 | 183 | Lint/UselessAccessModifier: 184 | Description: 'Checks for useless access modifiers.' 185 | Enabled: true 186 | 187 | Lint/UselessAssignment: 188 | Description: 'Checks for useless assignment to a local variable.' 189 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars' 190 | Enabled: true 191 | 192 | Lint/UselessComparison: 193 | Description: 'Checks for comparison of something with itself.' 194 | Enabled: true 195 | 196 | Lint/UselessElseWithoutRescue: 197 | Description: 'Checks for useless `else` in `begin..end` without `rescue`.' 198 | Enabled: true 199 | 200 | Lint/UselessSetterCall: 201 | Description: 'Checks for useless setter call to a local variable.' 202 | Enabled: true 203 | 204 | Lint/Void: 205 | Description: 'Possible use of operator/literal/variable in void context.' 206 | Enabled: true 207 | 208 | ###################### Metrics #################################### 209 | 210 | Metrics/AbcSize: 211 | Description: >- 212 | A calculated magnitude based on number of assignments, 213 | branches, and conditions. 214 | Reference: 'http://c2.com/cgi/wiki?AbcMetric' 215 | Enabled: false 216 | Max: 20 217 | 218 | Metrics/BlockNesting: 219 | Description: 'Avoid excessive block nesting' 220 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#three-is-the-number-thou-shalt-count' 221 | Enabled: true 222 | Max: 4 223 | 224 | Metrics/ClassLength: 225 | Description: 'Avoid classes longer than 250 lines of code.' 226 | Enabled: true 227 | Exclude: 228 | - 'test/**/*' 229 | Max: 250 230 | 231 | Metrics/CyclomaticComplexity: 232 | Description: >- 233 | A complexity metric that is strongly correlated to the number 234 | of test cases needed to validate a method. 235 | Enabled: true 236 | 237 | Metrics/LineLength: 238 | Description: 'Limit lines to 80 characters.' 239 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#80-character-limits' 240 | Enabled: false 241 | 242 | Metrics/MethodLength: 243 | Description: 'Avoid methods longer than 30 lines of code.' 244 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#short-methods' 245 | Enabled: true 246 | Max: 30 247 | 248 | Metrics/ModuleLength: 249 | Description: 'Avoid modules longer than 250 lines of code.' 250 | Enabled: true 251 | Max: 250 252 | 253 | Metrics/ParameterLists: 254 | Description: 'Avoid parameter lists longer than three or four parameters.' 255 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#too-many-params' 256 | Enabled: true 257 | 258 | Metrics/PerceivedComplexity: 259 | Description: >- 260 | A complexity metric geared towards measuring complexity for a 261 | human reader. 262 | Enabled: true 263 | 264 | ##################### Performance ############################# 265 | 266 | Performance/Count: 267 | Description: >- 268 | Use `count` instead of `select...size`, `reject...size`, 269 | `select...count`, `reject...count`, `select...length`, 270 | and `reject...length`. 271 | Enabled: true 272 | 273 | Performance/Detect: 274 | Description: >- 275 | Use `detect` instead of `select.first`, `find_all.first`, 276 | `select.last`, and `find_all.last`. 277 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code' 278 | Enabled: true 279 | 280 | Performance/FlatMap: 281 | Description: >- 282 | Use `Enumerable#flat_map` 283 | instead of `Enumerable#map...Array#flatten(1)` 284 | or `Enumberable#collect..Array#flatten(1)` 285 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code' 286 | Enabled: true 287 | EnabledForFlattenWithoutParams: false 288 | # If enabled, this cop will warn about usages of 289 | # `flatten` being called without any parameters. 290 | # This can be dangerous since `flat_map` will only flatten 1 level, and 291 | # `flatten` without any parameters can flatten multiple levels. 292 | 293 | Performance/ReverseEach: 294 | Description: 'Use `reverse_each` instead of `reverse.each`.' 295 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code' 296 | Enabled: true 297 | 298 | Performance/Sample: 299 | Description: >- 300 | Use `sample` instead of `shuffle.first`, 301 | `shuffle.last`, and `shuffle[Fixnum]`. 302 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code' 303 | Enabled: true 304 | 305 | Performance/Size: 306 | Description: >- 307 | Use `size` instead of `count` for counting 308 | the number of elements in `Array` and `Hash`. 309 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#arraycount-vs-arraysize-code' 310 | Enabled: true 311 | 312 | Performance/StringReplacement: 313 | Description: >- 314 | Use `tr` instead of `gsub` when you are replacing the same 315 | number of characters. Use `delete` instead of `gsub` when 316 | you are deleting characters. 317 | Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringgsub-vs-stringtr-code' 318 | Enabled: true 319 | 320 | ##################### Rails ################################## 321 | 322 | Rails/ActionFilter: 323 | Description: 'Enforces consistent use of action filter methods.' 324 | Enabled: false 325 | 326 | Rails/Date: 327 | Description: >- 328 | Checks the correct usage of date aware methods, 329 | such as Date.today, Date.current etc. 330 | Enabled: false 331 | 332 | Rails/Delegate: 333 | Description: 'Prefer delegate method for delegations.' 334 | Enabled: false 335 | 336 | Rails/FindBy: 337 | Description: 'Prefer find_by over where.first.' 338 | Enabled: false 339 | 340 | Rails/FindEach: 341 | Description: 'Prefer all.find_each over all.find.' 342 | Enabled: false 343 | 344 | Rails/HasAndBelongsToMany: 345 | Description: 'Prefer has_many :through to has_and_belongs_to_many.' 346 | Enabled: false 347 | 348 | Rails/Output: 349 | Description: 'Checks for calls to puts, print, etc.' 350 | Enabled: false 351 | 352 | Rails/ReadWriteAttribute: 353 | Description: >- 354 | Checks for read_attribute(:attr) and 355 | write_attribute(:attr, val). 356 | Enabled: false 357 | 358 | Rails/ScopeArgs: 359 | Description: 'Checks the arguments of ActiveRecord scopes.' 360 | Enabled: false 361 | 362 | Rails/TimeZone: 363 | Description: 'Checks the correct usage of time zone aware methods.' 364 | StyleGuide: 'https://github.com/bbatsov/rails-style-guide#time' 365 | Reference: 'http://danilenko.org/2012/7/6/rails_timezones' 366 | Enabled: false 367 | 368 | Rails/Validation: 369 | Description: 'Use validates :attribute, hash of validations.' 370 | Enabled: false 371 | 372 | ################## Style ################################# 373 | 374 | Style/AccessModifierIndentation: 375 | Description: Check indentation of private/protected visibility modifiers. 376 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#indent-public-private-protected' 377 | Enabled: true 378 | 379 | Style/AccessorMethodName: 380 | Description: Check the naming of accessor methods for get_/set_. 381 | Enabled: false 382 | 383 | Style/Alias: 384 | Description: 'Use alias_method instead of alias.' 385 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#alias-method' 386 | Enabled: false 387 | 388 | Style/AlignArray: 389 | Description: >- 390 | Align the elements of an array literal if they span more than 391 | one line. 392 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#align-multiline-arrays' 393 | Enabled: true 394 | 395 | Style/AlignHash: 396 | Description: >- 397 | Align the elements of a hash literal if they span more than 398 | one line. 399 | Enabled: true 400 | 401 | Style/AlignParameters: 402 | Description: >- 403 | Align the parameters of a method call if they span more 404 | than one line. WRONG! Only indent 2 (don't use this). 405 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-double-indent' 406 | Enabled: false 407 | 408 | Style/AndOr: 409 | Description: 'Use &&/|| instead of and/or.' 410 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-and-or-or' 411 | Enabled: false 412 | 413 | Style/ArrayJoin: 414 | Description: 'Use Array#join instead of Array#*.' 415 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#array-join' 416 | Enabled: true 417 | 418 | Style/AsciiComments: 419 | Description: 'Use only ascii symbols in comments.' 420 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-comments' 421 | Enabled: false 422 | 423 | Style/AsciiIdentifiers: 424 | Description: 'Use only ascii symbols in identifiers.' 425 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-identifiers' 426 | Enabled: false 427 | 428 | Style/Attr: 429 | Description: 'Checks for uses of Module#attr.' 430 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr' 431 | Enabled: true 432 | 433 | Style/BeginBlock: 434 | Description: 'Avoid the use of BEGIN blocks.' 435 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-BEGIN-blocks' 436 | Enabled: true 437 | 438 | Style/BarePercentLiterals: 439 | Description: 'Checks if usage of %() or %Q() matches configuration.' 440 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-q-shorthand' 441 | Enabled: true 442 | 443 | Style/BlockComments: 444 | Description: 'Do not use block comments.' 445 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-block-comments' 446 | Enabled: true 447 | 448 | Style/BlockEndNewline: 449 | Description: 'Put end statement of multiline block on its own line.' 450 | Enabled: true 451 | 452 | Style/BlockDelimiters: 453 | Description: >- 454 | Avoid using {...} for multi-line blocks (multiline chaining is 455 | always ugly). 456 | Prefer {...} over do...end for single-line blocks. 457 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#single-line-blocks' 458 | Enabled: true 459 | 460 | Style/BracesAroundHashParameters: 461 | Description: 'Enforce braces style around hash parameters.' 462 | Enabled: false 463 | 464 | Style/CaseEquality: 465 | Description: 'Avoid explicit use of the case equality operator(===).' 466 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-case-equality' 467 | Enabled: false 468 | 469 | Style/CaseIndentation: 470 | Description: 'Indentation of when in a case/when/[else/]end.' 471 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#indent-when-to-case' 472 | Enabled: true 473 | 474 | Style/CharacterLiteral: 475 | Description: 'Checks for uses of character literals.' 476 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-character-literals' 477 | Enabled: true 478 | 479 | Style/ClassAndModuleCamelCase: 480 | Description: 'Use CamelCase for classes and modules.' 481 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#camelcase-classes' 482 | Enabled: true 483 | 484 | Style/ClassAndModuleChildren: 485 | Description: 'Checks style of children classes and modules. This detests usage of ::' 486 | Enabled: false 487 | 488 | Style/ClassCheck: 489 | Description: 'Enforces consistent use of `Object#is_a?` or `Object#kind_of?`.' 490 | Enabled: false 491 | 492 | Style/ClassMethods: 493 | Description: 'Use self when defining module/class methods.' 494 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#def-self-class-methods' 495 | Enabled: true 496 | 497 | Style/ClassVars: 498 | Description: 'Avoid the use of class variables.' 499 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-class-vars' 500 | Enabled: true 501 | 502 | Style/ClosingParenthesisIndentation: 503 | Description: 'Checks the indentation of hanging closing parentheses. Faulty!' 504 | Enabled: false 505 | 506 | Style/ColonMethodCall: 507 | Description: 'Do not use :: for method call.' 508 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#double-colons' 509 | Enabled: true 510 | 511 | Style/CommandLiteral: 512 | Description: 'Use `` or %x around command literals.' 513 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-x' 514 | Enabled: true 515 | 516 | Style/CommentAnnotation: 517 | Description: 'Checks formatting of annotation comments.' 518 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#annotate-keywords' 519 | Enabled: false 520 | 521 | Style/CommentIndentation: 522 | Description: 'Indentation of comments.' 523 | Enabled: false 524 | 525 | Style/ConstantName: 526 | Description: 'Constants should use SCREAMING_SNAKE_CASE.' 527 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#screaming-snake-case' 528 | Enabled: false 529 | 530 | Style/DefWithParentheses: 531 | Description: 'Use def with parentheses when there are arguments.' 532 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#method-parens' 533 | Enabled: false 534 | 535 | Style/PreferredHashMethods: 536 | Description: 'Checks for use of deprecated Hash methods.' 537 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#hash-key' 538 | Enabled: true 539 | 540 | Style/Documentation: 541 | Description: 'Document classes and non-namespace modules.' 542 | Enabled: false 543 | 544 | Style/DotPosition: 545 | Description: 'Checks the position of the dot in multi-line method calls. WRONG CHOICE! NEED OPTION B!' 546 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains' 547 | Enabled: false 548 | 549 | Style/DoubleNegation: 550 | Description: 'Checks for uses of double negation (!!).' 551 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-bang-bang' 552 | Enabled: false 553 | 554 | Style/EachWithObject: 555 | Description: 'Prefer `each_with_object` over `inject` or `reduce`.' 556 | Enabled: false 557 | 558 | Style/ElseAlignment: 559 | Description: 'Align elses and elsifs correctly.' 560 | Enabled: true 561 | 562 | Style/EmptyElse: 563 | Description: 'Avoid empty else-clauses.' 564 | Enabled: true 565 | 566 | Style/EmptyLineBetweenDefs: 567 | Description: 'Use empty lines between defs.' 568 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#empty-lines-between-methods' 569 | Enabled: false 570 | 571 | Style/EmptyLines: 572 | Description: "Don't use several empty lines in a row." 573 | Enabled: true 574 | 575 | Style/EmptyLinesAroundAccessModifier: 576 | Description: "Keep blank lines around access modifiers. (eg: private)" 577 | Enabled: false 578 | 579 | Style/EmptyLinesAroundBlockBody: 580 | Description: "Keeps track of empty lines around block bodies." 581 | Enabled: false 582 | 583 | Style/EmptyLinesAroundClassBody: 584 | Description: "Keeps track of empty lines around class bodies." 585 | Enabled: false 586 | 587 | Style/EmptyLinesAroundModuleBody: 588 | Description: "Keeps track of empty lines around module bodies." 589 | Enabled: false 590 | 591 | Style/EmptyLinesAroundMethodBody: 592 | Description: "Keeps track of empty lines around method bodies." 593 | Enabled: false 594 | 595 | Style/EmptyLiteral: 596 | Description: 'Prefer literals to Array.new/Hash.new/String.new.' 597 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#literal-array-hash' 598 | Enabled: false 599 | 600 | Style/EndBlock: 601 | Description: 'Avoid the use of END blocks.' 602 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-END-blocks' 603 | Enabled: true 604 | 605 | Style/EndOfLine: 606 | Description: 'Use Unix-style line endings.' 607 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#crlf' 608 | Enabled: false 609 | 610 | Style/EvenOdd: 611 | Description: 'Favor the use of Fixnum#even? && Fixnum#odd?' 612 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods' 613 | Enabled: false 614 | 615 | Style/ExtraSpacing: 616 | Description: 'Do not use unnecessary spacing.' 617 | Enabled: true 618 | 619 | Style/FileName: 620 | Description: 'Use snake_case for source file names.' 621 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files' 622 | Enabled: true 623 | 624 | Style/InitialIndentation: 625 | Description: >- 626 | Checks the indentation of the first non-blank non-comment line in a file. 627 | Enabled: true 628 | 629 | Style/FirstParameterIndentation: 630 | Description: 'Checks the indentation of the first parameter in a method call.' 631 | Enabled: false 632 | 633 | Style/FlipFlop: 634 | Description: 'Checks for flip flops' 635 | StyleGuide: 'https://blog.newrelic.com/2015/02/24/weird-ruby-part-3-fun-flip-flop-phenom/' 636 | Enabled: true 637 | 638 | Style/For: 639 | Description: 'Checks use of for or each in multiline loops.' 640 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-for-loops' 641 | Enabled: true 642 | 643 | Style/FormatString: 644 | Description: 'Enforce the use of Kernel#sprintf, Kernel#format or String#%.' 645 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#sprintf' 646 | Enabled: false 647 | 648 | Style/GlobalVars: 649 | Description: 'Do not introduce global variables.' 650 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#instance-vars' 651 | Reference: 'http://www.zenspider.com/Languages/Ruby/QuickRef.html' 652 | Enabled: true 653 | 654 | Style/GuardClause: 655 | Description: 'Check for conditionals that can be replaced with guard clauses' 656 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals' 657 | Enabled: false 658 | 659 | Style/HashSyntax: 660 | Description: >- 661 | Prefer Ruby 1.9 hash syntax { a: 1, b: 2 } over 1.8 syntax 662 | { :a => 1, :b => 2 }. 663 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#hash-literals' 664 | Enabled: true 665 | 666 | Style/IfUnlessModifier: 667 | Description: >- 668 | Favor modifier if/unless usage when you have a 669 | single-line body. 670 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#if-as-a-modifier' 671 | Enabled: false 672 | 673 | Style/IfWithSemicolon: 674 | Description: 'Do not use if x; .... Use the ternary operator instead.' 675 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-semicolon-ifs' 676 | Enabled: true 677 | 678 | Style/IndentationConsistency: 679 | Description: 'Keep indentation straight.' 680 | Enabled: true 681 | 682 | Style/IndentationWidth: 683 | Description: 'Use 2 spaces for indentation.' 684 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-indentation' 685 | Enabled: true 686 | 687 | Style/IndentArray: 688 | Description: >- 689 | Checks the indentation of the first element in an array 690 | literal. 691 | Enabled: false 692 | 693 | Style/IndentHash: 694 | Description: 'Checks the indentation of the first key in a hash literal.' 695 | Enabled: false 696 | 697 | Style/InfiniteLoop: 698 | Description: 'Use Kernel#loop for infinite loops.' 699 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#infinite-loop' 700 | Enabled: true 701 | 702 | Style/Lambda: 703 | Description: 'Use the new lambda literal syntax for single-line blocks.' 704 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#lambda-multi-line' 705 | Enabled: true 706 | 707 | Style/LambdaCall: 708 | Description: 'Use lambda.call(...) instead of lambda.(...).' 709 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc-call' 710 | Enabled: false 711 | 712 | Style/LeadingCommentSpace: 713 | Description: 'Comments should start with a space.' 714 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#hash-space' 715 | Enabled: true 716 | 717 | Style/LineEndConcatenation: 718 | Description: >- 719 | Use \ instead of + or << to concatenate two string literals at 720 | line end. 721 | Enabled: true 722 | 723 | Style/MethodCallWithoutArgsParentheses: 724 | Description: 'Do not use parentheses for method calls with no arguments.' 725 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-args-no-parens' 726 | Enabled: false 727 | 728 | Style/MethodDefParentheses: 729 | Description: >- 730 | Checks if the method definitions have or don't have 731 | parentheses. 732 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#method-parens' 733 | Enabled: false 734 | 735 | Style/MethodName: 736 | Description: 'Use the configured style when naming methods.' 737 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-symbols-methods-vars' 738 | Enabled: true 739 | 740 | Style/ModuleFunction: 741 | Description: 'Checks for usage of `extend self` in modules.' 742 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#module-function' 743 | Enabled: true 744 | 745 | Style/MultilineBlockChain: 746 | Description: 'Avoid multi-line chains of blocks.' 747 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#single-line-blocks' 748 | Enabled: true 749 | 750 | Style/MultilineBlockLayout: 751 | Description: 'Ensures newlines after multiline block do statements.' 752 | Enabled: false 753 | 754 | Style/MultilineIfThen: 755 | Description: 'Do not use then for multi-line if/unless.' 756 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-then' 757 | Enabled: true 758 | 759 | Style/MultilineOperationIndentation: 760 | Description: >- 761 | Checks indentation of binary operations that span more than 762 | one line. 763 | Enabled: false 764 | 765 | Style/MultilineTernaryOperator: 766 | Description: >- 767 | Avoid multi-line ?: (the ternary operator); 768 | use if/unless instead. 769 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-multiline-ternary' 770 | Enabled: true 771 | 772 | Style/NegatedIf: 773 | Description: >- 774 | Favor unless over if for negative conditions 775 | (or control flow or). 776 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#unless-for-negatives' 777 | Enabled: false 778 | 779 | Style/NegatedWhile: 780 | Description: 'Favor until over while for negative conditions.' 781 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#until-for-negatives' 782 | Enabled: false 783 | 784 | Style/NestedTernaryOperator: 785 | Description: 'Use one expression per branch in a ternary operator.' 786 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-ternary' 787 | Enabled: true 788 | 789 | Style/Next: 790 | Description: 'Use `next` to skip iteration instead of a condition at the end.' 791 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals' 792 | Enabled: true 793 | 794 | Style/NilComparison: 795 | Description: 'Prefer x.nil? to x == nil.' 796 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods' 797 | Enabled: true 798 | 799 | Style/NonNilCheck: 800 | Description: 'Checks for redundant nil checks.' 801 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-non-nil-checks' 802 | Enabled: true 803 | 804 | Style/Not: 805 | Description: 'Use ! instead of not.' 806 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bang-not-not' 807 | Enabled: false 808 | 809 | Style/NumericLiterals: 810 | Description: >- 811 | Add underscores to large numeric literals to improve their 812 | readability. 813 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscores-in-numerics' 814 | Enabled: true 815 | 816 | Style/OneLineConditional: 817 | Description: >- 818 | Favor the ternary operator(?:) over 819 | if/then/else/end constructs. 820 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#ternary-operator' 821 | Enabled: true 822 | 823 | Style/OpMethod: 824 | Description: 'When defining binary operators, name the argument other.' 825 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg' 826 | Enabled: true 827 | 828 | Style/OptionalArguments: 829 | Description: >- 830 | Checks for optional arguments that do not appear at the end 831 | of the argument list 832 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#optional-arguments' 833 | Enabled: true 834 | 835 | Style/ParallelAssignment: 836 | Description: >- 837 | Check for simple usages of parallel assignment. 838 | It will only warn when the number of variables 839 | matches on both sides of the assignment. 840 | This also provides performance benefits 841 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parallel-assignment' 842 | Enabled: true 843 | 844 | Style/ParenthesesAroundCondition: 845 | Description: >- 846 | Don't use parentheses around the condition of an 847 | if/unless/while. 848 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-parens-if' 849 | Enabled: true 850 | 851 | Style/PercentLiteralDelimiters: 852 | Description: 'Use `%`-literal delimiters consistently' 853 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-literal-braces' 854 | Enabled: true 855 | 856 | Style/PercentQLiterals: 857 | Description: 'Checks if uses of %Q/%q match the configured preference.' 858 | Enabled: true 859 | 860 | Style/PerlBackrefs: 861 | Description: 'Avoid Perl-style regex back references.' 862 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers' 863 | Enabled: true 864 | 865 | Style/PredicateName: 866 | Description: 'Check the names of predicate methods.' 867 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark' 868 | Enabled: false 869 | 870 | Style/Proc: 871 | Description: 'Use proc instead of Proc.new.' 872 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc' 873 | Enabled: false 874 | 875 | Style/RaiseArgs: 876 | Description: 'Checks the arguments passed to raise/fail.' 877 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#exception-class-messages' 878 | Enabled: true 879 | 880 | Style/RedundantBegin: 881 | Description: "Don't use begin blocks when they are not needed." 882 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#begin-implicit' 883 | Enabled: true 884 | 885 | Style/RedundantException: 886 | Description: "Checks for an obsolete RuntimeException argument in raise/fail." 887 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-explicit-runtimeerror' 888 | Enabled: true 889 | 890 | Style/RedundantReturn: 891 | Description: "Don't use return where it's not required." 892 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-explicit-return' 893 | Enabled: true 894 | 895 | Style/RedundantSelf: 896 | Description: "Don't use self where it's not needed." 897 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-self-unless-required' 898 | Enabled: true 899 | 900 | Style/RegexpLiteral: 901 | Description: 'Use / or %r around regular expressions.' 902 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-r' 903 | Enabled: true 904 | 905 | Style/RescueEnsureAlignment: 906 | Description: 'Align rescues and ensures correctly.' 907 | Enabled: true 908 | 909 | Style/RescueModifier: 910 | Description: 'Avoid using rescue in its modifier form.' 911 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-rescue-modifiers' 912 | Enabled: true 913 | 914 | Style/SelfAssignment: 915 | Description: >- 916 | Checks for places where self-assignment shorthand should have 917 | been used. 918 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#self-assignment' 919 | Enabled: false 920 | 921 | Style/Semicolon: 922 | Description: "Don't use semicolons to terminate expressions." 923 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-semicolon' 924 | Enabled: false 925 | 926 | Style/SignalException: 927 | Description: 'Checks for proper usage of fail and raise.' 928 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#fail-method' 929 | Enabled: true 930 | 931 | Style/SingleLineBlockParams: 932 | Description: 'Enforces the names of some block params.' 933 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#reduce-blocks' 934 | Enabled: false 935 | 936 | Style/SingleLineMethods: 937 | Description: 'Avoid single-line methods.' 938 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-single-line-methods' 939 | Enabled: false 940 | 941 | Style/SpaceBeforeFirstArg: 942 | Description: >- 943 | Checks that exactly one space is used between a method name 944 | and the first argument for method calls without parentheses. 945 | Enabled: true 946 | 947 | Style/SpaceAfterColon: 948 | Description: 'Use spaces after colons.' 949 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-operators' 950 | Enabled: true 951 | 952 | Style/SpaceAfterComma: 953 | Description: 'Use spaces after commas.' 954 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-operators' 955 | Enabled: true 956 | 957 | Style/SpaceAroundKeyword: 958 | Description: 'Use spaces around keywords.' 959 | Enabled: true 960 | 961 | Style/SpaceAfterMethodName: 962 | Description: >- 963 | Do not put a space between a method name and the opening 964 | parenthesis in a method definition. 965 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces' 966 | Enabled: true 967 | 968 | Style/SpaceAfterNot: 969 | Description: Tracks redundant space after the ! operator. 970 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-space-bang' 971 | Enabled: true 972 | 973 | Style/SpaceAfterSemicolon: 974 | Description: 'Use spaces after semicolons.' 975 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-operators' 976 | Enabled: true 977 | 978 | Style/SpaceBeforeBlockBraces: 979 | Description: >- 980 | Checks that the left block brace has or doesn't have space 981 | before it. 982 | Enabled: false 983 | 984 | Style/SpaceBeforeComma: 985 | Description: 'No spaces before commas.' 986 | Enabled: true 987 | 988 | Style/SpaceBeforeComment: 989 | Description: >- 990 | Checks for missing space between code and a comment on the 991 | same line. 992 | Enabled: true 993 | 994 | Style/SpaceBeforeSemicolon: 995 | Description: 'No spaces before semicolons.' 996 | Enabled: true 997 | 998 | Style/SpaceInsideBlockBraces: 999 | Description: >- 1000 | Checks that block braces have or don't have surrounding space. 1001 | For blocks taking parameters, checks that the left brace has 1002 | or doesn't have trailing space. 1003 | Enabled: false 1004 | 1005 | Style/SpaceAroundBlockParameters: 1006 | Description: 'Checks the spacing inside and after block parameters pipes.' 1007 | Enabled: true 1008 | 1009 | Style/SpaceAroundEqualsInParameterDefault: 1010 | Description: >- 1011 | Checks that the equals signs in parameter default assignments 1012 | have or don't have surrounding space depending on 1013 | configuration. 1014 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-around-equals' 1015 | Enabled: false 1016 | 1017 | Style/SpaceAroundOperators: 1018 | Description: 'Use a single space around operators.' 1019 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-operators' 1020 | Enabled: false 1021 | 1022 | Style/SpaceInsideBrackets: 1023 | Description: 'No spaces after [ or before ].' 1024 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-spaces-braces' 1025 | Enabled: false 1026 | 1027 | Style/SpaceInsideHashLiteralBraces: 1028 | Description: "Use spaces inside hash literal braces - or don't." 1029 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-operators' 1030 | Enabled: false 1031 | 1032 | Style/SpaceInsideParens: 1033 | Description: 'No spaces after ( or before ).' 1034 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-spaces-braces' 1035 | Enabled: false 1036 | 1037 | Style/SpaceInsideRangeLiteral: 1038 | Description: 'No spaces inside range literals.' 1039 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-space-inside-range-literals' 1040 | Enabled: false 1041 | 1042 | Style/SpaceInsideStringInterpolation: 1043 | Description: 'Checks for padding/surrounding spaces inside string interpolation.' 1044 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#string-interpolation' 1045 | Enabled: false 1046 | 1047 | Style/SpecialGlobalVars: 1048 | Description: 'Avoid Perl-style global variables.' 1049 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-cryptic-perlisms' 1050 | Enabled: true 1051 | 1052 | Style/StringLiterals: 1053 | Description: 'Checks if uses of quotes match the configured preference.' 1054 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-string-literals' 1055 | Enabled: false 1056 | 1057 | Style/StringLiteralsInInterpolation: 1058 | Description: >- 1059 | Checks if uses of quotes inside expressions in interpolated 1060 | strings match the configured preference. 1061 | Enabled: false 1062 | 1063 | Style/StructInheritance: 1064 | Description: 'Checks for inheritance from Struct.new.' 1065 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-extend-struct-new' 1066 | Enabled: true 1067 | 1068 | Style/SymbolLiteral: 1069 | Description: 'Use plain symbols instead of string symbols when possible.' 1070 | Enabled: true 1071 | 1072 | Style/SymbolProc: 1073 | Description: 'Use symbols as procs instead of blocks when possible.' 1074 | Enabled: false 1075 | 1076 | Style/Tab: 1077 | Description: 'No hard tabs.' 1078 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-indentation' 1079 | Enabled: true 1080 | 1081 | Style/TrailingBlankLines: 1082 | Description: 'Checks trailing blank lines and final newline.' 1083 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#newline-eof' 1084 | Enabled: true 1085 | 1086 | Style/TrailingCommaInArguments: 1087 | Description: 'Checks for trailing comma in parameter lists.' 1088 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-params-comma' 1089 | Enabled: false 1090 | 1091 | Style/TrailingCommaInLiteral: 1092 | Description: 'Checks for trailing comma in literals.' 1093 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas' 1094 | Enabled: false 1095 | 1096 | Style/TrailingWhitespace: 1097 | Description: 'Avoid trailing whitespace.' 1098 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-whitespace' 1099 | Enabled: true 1100 | 1101 | Style/TrivialAccessors: 1102 | Description: 'Prefer attr_* methods to trivial readers/writers.' 1103 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr_family' 1104 | Enabled: false 1105 | 1106 | Style/UnlessElse: 1107 | Description: >- 1108 | Do not use unless with else. Rewrite these with the positive 1109 | case first. 1110 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-else-with-unless' 1111 | Enabled: true 1112 | 1113 | Style/UnneededCapitalW: 1114 | Description: 'Checks for %W when interpolation is not needed.' 1115 | Enabled: true 1116 | 1117 | Style/UnneededPercentQ: 1118 | Description: 'Checks for %q/%Q when single quotes or double quotes would do.' 1119 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-q' 1120 | Enabled: true 1121 | 1122 | Style/TrailingUnderscoreVariable: 1123 | Description: >- 1124 | Checks for the usage of unneeded trailing underscores at the 1125 | end of parallel variable assignment. 1126 | Enabled: false 1127 | 1128 | Style/VariableInterpolation: 1129 | Description: >- 1130 | Don't interpolate global, instance and class variables 1131 | directly in strings. 1132 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#curlies-interpolate' 1133 | Enabled: true 1134 | 1135 | Style/VariableName: 1136 | Description: 'Use the configured style when naming variables.' 1137 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-symbols-methods-vars' 1138 | Enabled: true 1139 | 1140 | Style/WhenThen: 1141 | Description: 'Use when x then ... for one-line cases.' 1142 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#one-line-cases' 1143 | Enabled: true 1144 | 1145 | Style/WhileUntilDo: 1146 | Description: 'Checks for redundant do after while or until.' 1147 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-multiline-while-do' 1148 | Enabled: true 1149 | 1150 | Style/WhileUntilModifier: 1151 | Description: >- 1152 | Favor modifier while/until usage when you have a 1153 | single-line body. 1154 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#while-as-a-modifier' 1155 | Enabled: true 1156 | 1157 | Style/WordArray: 1158 | Description: 'Use %w or %W for arrays of words.' 1159 | StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-w' 1160 | Enabled: false 1161 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.2.6 4 | - 2.3.3 5 | env: 6 | matrix: 7 | - RAILS_VERSION=4.1.10 8 | - RAILS_VERSION=4.2.1 9 | global: 10 | - secure: qXpWydxv6DHMrvGL8WH4wNRY4MTY7KV/x308Y5dHkZCrI7k9UOccvznp69KT3Z+tzYEFDXfUix5wA6pgyVcvrsQyiLSjGcyzHhxJKs1gk0gcxAkmhwHmUP9aiXWUe/mzpj7Uoc2DHwpPTpK1wQ5kV6eV+jzQLuN3nhfNr2sL8b4= 11 | addons: 12 | code_climate: 13 | repo_token: eb4024a12a427920a8f9c81d1ad5a3b3f571503f3c64f0bde04eaad3bf5c564f 14 | script: bundle exec rake test 15 | after_success: 16 | - bundle exec codeclimate-test-reporter 17 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | For you, brethren, have been called to liberty; only do not use liberty as an opportunity for the flesh, but through love serve one another. For all the law is fulfilled in one word, even in this: “You shall love your neighbor as yourself.” But if you bite and devour one another, beware lest you be consumed by one another! - [Galatians 5:13-15](https://www.biblegateway.com/passage/?search=Gal.5.13-Gal.5.15&version=NKJV) 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | group :test do 6 | gem 'simplecov' 7 | gem "codeclimate-test-reporter", '~> 1.0.0' 8 | end 9 | 10 | group :development, :test do 11 | rails_version = ENV["RAILS_VERSION"] || "default" 12 | # if rails_version =~ /^3\./ 13 | # gem 'test-unit', ">= 1.2.3" 14 | # end 15 | rails = case rails_version 16 | when "master" 17 | {github: "rails/rails"} 18 | when "default" 19 | ">= 3.1.0" 20 | else 21 | "~> #{rails_version}" 22 | end 23 | gem "rails", rails 24 | gem 'color_pound_spec_reporter', '~> 0.0.5' 25 | end 26 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015-2017 Daniel P. Clark 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PolyBelongsTo 2 | 3 | [![Gem Version](https://badge.fury.io/rb/poly_belongs_to.svg)](http://badge.fury.io/rb/poly_belongs_to) 4 | [![Code Climate](https://codeclimate.com/github/danielpclark/PolyBelongsTo/badges/gpa.svg)](https://codeclimate.com/github/danielpclark/PolyBelongsTo) 5 | [![Build Status](https://travis-ci.org/danielpclark/PolyBelongsTo.svg)](https://travis-ci.org/danielpclark/PolyBelongsTo) 6 | [![Test Coverage](https://codeclimate.com/github/danielpclark/PolyBelongsTo/badges/coverage.svg)](https://codeclimate.com/github/danielpclark/PolyBelongsTo) 7 | [![Inline docs](http://inch-ci.org/github/danielpclark/PolyBelongsTo.svg?branch=master)](http://inch-ci.org/github/danielpclark/PolyBelongsTo) 8 | [![Featured In Ruby Weekly #233](https://img.shields.io/badge/Featured%20In-Ruby%20Weekly%20%23233-brightgreen.svg)](http://rubyweekly.com/issues/233) 9 | [![Featured In Green Ruby #118](https://img.shields.io/badge/Featured%20In-Green%20Ruby%20%23118-brightgreen.svg)](http://greenruby.org/grn-118.html) 10 | [![SayThanks.io](https://img.shields.io/badge/SayThanks.io-%E2%98%BC-1EAEDB.svg)](https://saythanks.io/to/danielpclark) 11 | 12 | **Original Purpose:** A standard way to check belongs_to relations on any belongs_to Object and let you check your DB Objects polymorphism in a more across-the-board meta-programatically friendly way. 13 | 14 | PolyBelongsTo has grown into a powerful tool for working with all kinds of ActiveRecord relationships and situations. PBT makes handling things in AR easier to deal with in a more generic way. There are also some hierarchal tools provided which make coding with AR relationships all the more powerful. See anything that's missing? Please open an issue and suggest a feature! 15 | 16 | **Database integrity** can be checked with a few methods to find orphaned record relations and incorrectly typed polymorphic relations. 17 | 18 | **Deep cloning** of records with associations is an added feature this gem provides. It requires no configuration to use, you can simply invoke: `pbt_deep_dup_build`. This makes for much easier record duplication than the [deep_cloneable](https://github.com/moiristo/deep_cloneable) gem. 19 | 20 | # Installation 21 | 22 | Just include it in your Gemfile and then run bundle: 23 | ```ruby 24 | gem 'poly_belongs_to', '~> 1.0' 25 | ``` 26 | 27 | ## Recommended Usage 28 | 29 | ##### On model class 30 | ```ruby 31 | # Is Polymorphic? 32 | MyOject.poly? 33 | # => true 34 | User.poly? 35 | # => false 36 | 37 | # Belongs To Relation Table 38 | MyObject.pbt 39 | # => :my_objectable 40 | User.pbt 41 | # => nil 42 | 43 | # Multiple Belongs To Relations 44 | Tire.pbts 45 | # => [:user, :car] 46 | 47 | # Multiple Has One Relations 48 | Profile.has_one_of 49 | # => [:photo] 50 | 51 | # Multiple Has Many Relations 52 | Profile.has_many_of 53 | # => [:phones, :addresses] 54 | 55 | # Multiple Has And Belongs To Many Relations 56 | Assembly.habtm_of 57 | # => [:parts] 58 | 59 | # Get orphaned objects for records of class type 60 | MyObject.pbt_orphans 61 | # => # # nil for objects without belongs_to 62 | 63 | # Get polymorphic objects for records of invalid class type(s) 64 | MyObject.pbt_mistyped 65 | # => # 66 | 67 | # Get the invalid class types on polymorphic records as a Array of Strings 68 | MyObject.pbt_mistypes 69 | # => ["Object", "Class", "MyObjectable"] 70 | 71 | # Get the valid class types on polymorphic records as a Array of Strings 72 | MyObject.pbt_valid_types 73 | # => ["User", "MyObject"] 74 | 75 | # Params name 76 | MyObject.pbt_params_name 77 | # => :my_objectable_attributes 78 | MyObject.pbt_params_name(false) 79 | # => :my_object 80 | User.pbt_params_name 81 | # => :user 82 | 83 | # DB column names 84 | MyObject.pbt_id_sym 85 | # => :my_objectable_id 86 | MyObject.pbt_type_sym 87 | # => :my_objectable_type # nil for non polymorphic Objects 88 | ``` 89 | ##### On model instances 90 | ```ruby 91 | # Belongs To Relations ID 92 | MyObject.first.pbt_id 93 | # => 123 94 | 95 | # Polymorphic Belongs To Relations Type 96 | MyObject.first.pbt_type 97 | "User" # nil for non polymorphic Objects 98 | 99 | # Get Parent Object (Works on all belongs_to Objects) 100 | MyObject.first.pbt_parent 101 | # => # 102 | 103 | # Get Top Hierarchical Parent Object (Works on all belongs_to Objects) 104 | MyObject.first.pbt_top_parent 105 | # => # 106 | 107 | # Mutliple Parent Objects (List of one item for Polymorphic, full list otherwise.) 108 | Tire.first.pbt_parents 109 | # => [#, #] 110 | 111 | # Determine if object is orphaned (parent no longer exists) 112 | Tire.first.orphan? 113 | # => false 114 | ``` 115 | 116 | ## Also Available 117 | ```ruby 118 | # --- Model Instances --- 119 | # NOTE: touches db if object isn't already instantiated 120 | 121 | # Is Polymorphic? 122 | MyObject.new.poly? 123 | # => true 124 | User.first.poly? 125 | # => false 126 | 127 | # Belongs To Relation Table 128 | MyObject.new.pbt 129 | # => :my_objectable 130 | User.first.pbt 131 | # => nil 132 | 133 | # Multiple Belongs To Relations 134 | Tire.first.pbts 135 | # => [:user, :car] 136 | 137 | # Params name 138 | MyObject.new.pbt_params_name 139 | # => :my_objectable_attributes 140 | MyObject.new.pbt_params_name(false) 141 | # => :my_object 142 | User.first.pbt_params_name 143 | # => :user 144 | 145 | # DB column names 146 | MyObject.new.pbt_id_sym 147 | # => :my_objectable_id 148 | MyObject.new.pbt_type_sym # nil for non polymorphic Objects 149 | # => :my_objectable_type 150 | ``` 151 | 152 | ## Internal Methods Available 153 | 154 | ```ruby 155 | # For cleaning attributes for use with build 156 | PolyBelongsTo::Pbt::AttrSanitizer[ obj ] 157 | 158 | # Returns string of either 'child.build' or 'build_child' 159 | PolyBelongsTo::Pbt::BuildCmd[ obj, child ] 160 | 161 | # Returns has_one and has_many relationships for obj as an Array of symbols 162 | PolyBelongsTo::Pbt::Reflects[ obj, habtm = false ] 163 | 164 | # Returns Class Ojects for each has_one and has_many child associations 165 | PolyBelongsTo::Pbt::ReflectsAsClasses[ obj, habtm = false ] 166 | 167 | # Boolean of whether child object/class is a has(one/many) relationship to obj 168 | PolyBelongsTo::Pbt::IsReflected[ obj, child ] 169 | 170 | # Returns :singular if obj->child is has_one and :plural if obj->child is has_many 171 | PolyBelongsTo::Pbt::SingularOrPlural[ obj, child ] 172 | 173 | # Returns true if obj->child relationship is has_one 174 | PolyBelongsTo::Pbt::IsSingular[ obj, child ] 175 | 176 | # Returns true if obj->child relationship is has_many 177 | PolyBelongsTo::Pbt::IsPlural[ obj, child ] 178 | 179 | # Returns the symbol for the CollectionProxy the child belongs to in relation to obj 180 | # NOTE: For has_one the symbol is not a CollectionProxy, but represents the instance 181 | PolyBelongsTo::Pbt::CollectionProxy[ obj, child ] 182 | 183 | # Always returns a collection proxy; fakes a collection proxy for has_one 184 | PolyBelongsTo::Pbt::AsCollectionProxy[ obj, child ] 185 | 186 | # Wrapper for has_one objects to be a collection proxy 187 | PolyBelongsTo::FakedCollection.new(obj, child) 188 | 189 | # Track which DB records have already been processed 190 | PolyBelongsTo::SingletonSet.new 191 | ``` 192 | > In methods that have more than one type of ownership the order or precedence is 193 | polymorphic relationships first, primary key next (or first reflection in lookup). 194 | 195 | 196 | ## Record Duplication 197 | 198 | **This gives you the advantage of duplicating records regardless of polymorphic associations or 199 | otherwise**. You can duplicate a record, or use a self recursive command **pbt_deep_dup_build** 200 | to duplicate a record and all of it's has_one/has_many children records at once. Afterwards 201 | be sure to use the save method. 202 | 203 | 204 | #### Known Issues 205 | - Carrierwave records won't duplicate. To ensure that other records will still save and 206 | prevent any rollback issues use .save(validate: false) ... I'm considering possible options 207 | to remedy this and 208 | other scenarios. 209 | 210 | ### How To Use 211 | 212 | Use the dup/build methods as follows 213 | 214 | ```ruby 215 | # If you were to create a new contact for example 216 | contact = User.first.contacts.new 217 | 218 | # This is just like contact.profile.build( { ... user's profile attributes ... } ) 219 | contact.pbt_dup_build( User.last.profile ) 220 | 221 | # Save it! 222 | contact.save 223 | 224 | 225 | # For a fully recursive copy do the same with pbt_deep_dup_build 226 | contact.pbt_deep_dup_build( User.last.profile ) 227 | 228 | # Remeber to save! 229 | contact.save 230 | ``` 231 | 232 | ## Contributing 233 | 234 | Feel free to fork and make pull requests. Please bring up an issue before a pull 235 | request if it's a non-fix change. Please add applicable fixtures and tests for 236 | any new features/implementations you add. 237 | 238 | Thank You! 239 | 240 | 241 | # License 242 | 243 | The MIT License (MIT) 244 | 245 | Copyright (C) 2015-2017 by Daniel P. Clark 246 | 247 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 248 | 249 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 250 | 251 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 252 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | begin 2 | require 'bundler/setup' 3 | rescue LoadError 4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 5 | end 6 | 7 | require 'rdoc/task' 8 | 9 | RDoc::Task.new(:rdoc) do |rdoc| 10 | rdoc.rdoc_dir = 'rdoc' 11 | rdoc.title = 'PolyBelongsTo' 12 | rdoc.options << '--line-numbers' 13 | rdoc.rdoc_files.include('README.rdoc') 14 | rdoc.rdoc_files.include('lib/**/*.rb') 15 | end 16 | 17 | Bundler::GemHelper.install_tasks 18 | 19 | require 'rake/testtask' 20 | 21 | Rake::TestTask.new(:test) do |t| 22 | t.libs << 'lib' 23 | t.libs << 'test' 24 | t.pattern = 'test/**/*_test.rb' 25 | t.verbose = false 26 | end 27 | 28 | task default: :test 29 | -------------------------------------------------------------------------------- /lib/poly_belongs_to.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH << File.join(File.dirname(__FILE__), "/poly_belongs_to") 2 | require 'active_support/concern' 3 | require 'poly_belongs_to/sorted_reflection_decorator' 4 | ActiveRecord::Reflection::ClassMethods.send(:include, PolyBelongsTo::SortedReflectionDecorator ) 5 | require 'poly_belongs_to/version' 6 | require 'poly_belongs_to/core' 7 | require 'poly_belongs_to/singleton_set' 8 | require 'poly_belongs_to/dup' 9 | require 'poly_belongs_to/pbt' 10 | require 'poly_belongs_to/faked_collection' 11 | ActiveRecord::Base.send(:include, PolyBelongsTo::Core ) 12 | ActiveRecord::Base.send(:include, PolyBelongsTo::Dup ) 13 | 14 | ## 15 | # 16 | # PolyBelongsTo 17 | # @author Daniel P. Clark 18 | # 19 | # Creates uniform helper methods on all ActiveModel & ActiveRecord instances 20 | # to allow universal access and control over (most) any kind of database 21 | # relationship. 22 | # 23 | # PolyBelongsTo::Core and PolyBelongsTo::Dup methods are included on each instance. 24 | # @see PolyBelongsTo::Core 25 | # @see PolyBelongsTo::Dup 26 | # 27 | module PolyBelongsTo end 28 | -------------------------------------------------------------------------------- /lib/poly_belongs_to/core.rb: -------------------------------------------------------------------------------- 1 | module PolyBelongsTo 2 | ## 3 | # PolyBelongsTo::Core are the core set of methods included on all ActiveModel & ActiveRecord instances. 4 | module Core 5 | extend ActiveSupport::Concern 6 | 7 | included do 8 | # @return [Symbol, nil] first belongs_to relation 9 | def self.pbt 10 | reflect_on_all_associations(:belongs_to).first.try(:name) 11 | end 12 | 13 | # @return [Array] belongs_to relations 14 | def self.pbts 15 | reflect_on_all_associations(:belongs_to).map(&:name) 16 | end 17 | 18 | # @return [Array] has_one relations 19 | def self.has_one_of 20 | reflect_on_all_associations(:has_one).map(&:name) 21 | end 22 | 23 | # @return [Array] has_many relations 24 | def self.has_many_of 25 | reflect_on_all_associations(:has_many).map(&:name) 26 | end 27 | 28 | # @return [Array] has_many relations 29 | def self.habtm_of 30 | reflect_on_all_associations(:has_and_belongs_to_many).map(&:name) 31 | end 32 | 33 | # Boolean reponse of current class being polymorphic 34 | # @return [true, false] 35 | def self.poly? 36 | !!reflect_on_all_associations(:belongs_to).first.try {|i| i.options[:polymorphic] } 37 | end 38 | 39 | # Symbol for html form params 40 | # @param allow_as_nested [true, false] Allow parameter name to be nested attribute symbol 41 | # @return [Symbol] The symbol for the form in the view 42 | def self.pbt_params_name(allow_as_nested = true) 43 | if poly? && allow_as_nested 44 | "#{table_name}_attributes".to_sym 45 | else 46 | name.downcase.to_sym 47 | end 48 | end 49 | 50 | # The symbol as an id field for the first belongs_to relation 51 | # @return [Symbol, nil] :`belongs_to_object`_id or nil 52 | def self.pbt_id_sym 53 | val = pbt 54 | val ? "#{val}_id".to_sym : nil 55 | end 56 | 57 | # The symbol as an sym field for the polymorphic belongs_to relation, or nil 58 | # @return [Symbol, nil] :`belongs_to_object`_sym or nil 59 | def self.pbt_type_sym 60 | poly? ? "#{pbt}_type".to_sym : nil 61 | end 62 | 63 | # Returns an unique array of strings of every polymorphic record type 64 | # @return [Array] 65 | def self.pbt_poly_types 66 | return [] unless poly? 67 | uniq.pluck(pbt_type_sym) 68 | end 69 | 70 | # Returns strings of the invalid class names stored in polymorphic records 71 | # @return [Array] 72 | def self.pbt_mistypes 73 | pbt_poly_types.select do |i| 74 | begin 75 | !i.constantize.respond_to?(:pluck) 76 | rescue 77 | true 78 | end 79 | end 80 | end 81 | 82 | # Returns strings of the valid class names stored in polymorphic records 83 | # @return [Array] 84 | def self.pbt_valid_types 85 | pbt_poly_types.delete_if do |i| 86 | begin 87 | !i.constantize.respond_to?(:pluck) 88 | rescue 89 | true 90 | end 91 | end 92 | end 93 | 94 | # Returns records with invalid class names stored in polymorphic records 95 | # @return [Array, nil] ActiveRecord mistyped objects 96 | def self.pbt_mistyped 97 | return nil unless poly? 98 | where(pbt_type_sym => pbt_mistypes) 99 | end 100 | 101 | # Return Array of current Class records that are orphaned from parents 102 | # @return [Array, nil] ActiveRecord orphan objects 103 | def self.pbt_orphans 104 | return nil unless pbts.present? 105 | poly? ? _pbt_polymorphic_orphans : _pbt_nonpolymorphic_orphans 106 | end 107 | 108 | private 109 | # Return Array of current Class polymorphic records that are orphaned from parents 110 | # @return [Array] ActiveRecord orphan objects 111 | def self._pbt_polymorphic_orphans 112 | accumulative = nil 113 | pbt_valid_types.each do |type| 114 | arel_part = arel_table[pbt_id_sym].not_in(type.constantize.arel_table.project(:id)).and(arel_table[pbt_type_sym].eq(type)) 115 | accumulative = accumulative.present? ? accumulative.or(arel_part) : arel_part 116 | end 117 | where(accumulative) 118 | end 119 | 120 | # Return Array of current Class nonpolymorphic records that are orphaned from parents 121 | # @return [Array] ActiveRecord orphan objects 122 | def self._pbt_nonpolymorphic_orphans 123 | where(arel_table[pbt_id_sym].not_in(pbt.to_s.camelize.constantize.arel_table.project(:id))) 124 | end 125 | class << self 126 | private :_pbt_polymorphic_orphans 127 | private :_pbt_nonpolymorphic_orphans 128 | end 129 | end 130 | 131 | # @return [Symbol, nil] first belongs_to relation 132 | def pbt 133 | self.class.pbt 134 | end 135 | 136 | # @return [Array] belongs_to relations 137 | def pbts 138 | self.class.pbts 139 | end 140 | 141 | # Boolean reponse of current class being polymorphic 142 | # @return [true, false] 143 | def poly? 144 | self.class.poly? 145 | end 146 | 147 | # Value of parent id. nil if no parent 148 | # @return [Integer, nil] 149 | def pbt_id 150 | val = pbt 151 | val ? send("#{val}_id") : nil 152 | end 153 | 154 | # Value of polymorphic relation type. nil if not polymorphic. 155 | # @return [String, nil] 156 | def pbt_type 157 | poly? ? send("#{pbt}_type") : nil 158 | end 159 | 160 | # Get the parent relation. Polymorphic relations are prioritized first. 161 | # @return [Object, nil] ActiveRecord object instasnce 162 | def pbt_parent 163 | val = pbt 164 | if val && !pbt_id.nil? 165 | if poly? 166 | "#{pbt_type}".constantize.where(id: pbt_id).first 167 | else 168 | "#{val}".camelize.constantize.where(id: pbt_id).first 169 | end 170 | end 171 | end 172 | 173 | # Climb up each parent object in the hierarchy until the top is reached. 174 | # This has a no-repeat safety built in. Polymorphic parents have priority. 175 | # @return [Object, nil] top parent ActiveRecord object instace 176 | def pbt_top_parent 177 | record = self 178 | return nil unless record.pbt_parent 179 | no_repeat = PolyBelongsTo::SingletonSet.new 180 | while !no_repeat.include?(record.pbt_parent) && !record.pbt_parent.nil? 181 | no_repeat.add?(record) 182 | record = record.pbt_parent 183 | end 184 | record 185 | end 186 | 187 | # All belongs_to parents as class objects. One if polymorphic. 188 | # @return [Array] ActiveRecord classes of parent objects. 189 | def pbt_parents 190 | if poly? 191 | Array[pbt_parent].compact 192 | else 193 | self.class.pbts.map do |i| 194 | try{ "#{i}".camelize.constantize.where(id: send("#{i}_id")).first } 195 | end.compact 196 | end 197 | end 198 | 199 | # The symbol as an id field for the first belongs_to relation 200 | # @return [Symbol, nil] :`belongs_to_object`_id or nil 201 | def pbt_id_sym 202 | self.class.pbt_id_sym 203 | end 204 | 205 | # The symbol as an sym field for the polymorphic belongs_to relation, or nil 206 | # @return [Symbol, nil] :`belongs_to_object`_sym or nil 207 | def pbt_type_sym 208 | self.class.pbt_type_sym 209 | end 210 | 211 | # Symbol for html form params 212 | # @param allow_as_nested [true, false] Allow parameter name to be nested attribute symbol 213 | # @return [Symbol] The symbol for the form in the view 214 | def pbt_params_name(allow_as_nested = true) 215 | self.class.pbt_params_name(allow_as_nested) 216 | end 217 | 218 | # Return true or false on whether the record is orphaned 219 | # @return [Boolean 220 | def orphan? 221 | pbts.present? && !pbt_parent.present? 222 | end 223 | end 224 | end 225 | -------------------------------------------------------------------------------- /lib/poly_belongs_to/dup.rb: -------------------------------------------------------------------------------- 1 | module PolyBelongsTo 2 | ## 3 | # PolyBelongsTo::Dup contains duplication methods which is included on all ActiveModel & ActiveRecord instances 4 | module Dup 5 | extend ActiveSupport::Concern 6 | 7 | included do 8 | # Build child object by dup'ing its attributes 9 | # @param item_to_build_on [Object] Object on which to build on 10 | # @param item_to_duplicate [Object] Object to duplicate as new child 11 | def self.pbt_dup_build(item_to_build_on, item_to_duplicate) 12 | singleton_record = yield if block_given? 13 | if PolyBelongsTo::Pbt::IsReflected[item_to_build_on, item_to_duplicate] 14 | PolyBelongsTo::Pbt::AsCollectionProxy[item_to_build_on, item_to_duplicate]. 15 | build PolyBelongsTo::Pbt::AttrSanitizer[item_to_duplicate] if 16 | block_given? ? singleton_record.add?(item_to_duplicate) : true 17 | end 18 | end 19 | 20 | # Build child object by dup'ing its attributes. Recursive for ancestry tree. 21 | # @param item_to_build_on [Object] Object on which to build on 22 | # @param item_to_duplicate [Object] Object to duplicate as new child along with child ancestors 23 | def self.pbt_deep_dup_build(item_to_build_on, item_to_duplicate) 24 | singleton_record = (block_given? ? yield : PolyBelongsTo::SingletonSet.new) 25 | pbt_dup_build(item_to_build_on, item_to_duplicate) {singleton_record} 26 | PolyBelongsTo::Pbt::Reflects[item_to_duplicate].each do |ref| 27 | child = item_to_duplicate.send(ref) 28 | PolyBelongsTo::Pbt::AsCollectionProxy[item_to_build_on, item_to_duplicate]. 29 | each do |builder| 30 | if child.respond_to?(:build) 31 | child.each do |spawn| 32 | builder.pbt_deep_dup_build(spawn) {singleton_record} 33 | end 34 | else 35 | builder.pbt_deep_dup_build(child) {singleton_record} 36 | end 37 | end 38 | end 39 | item_to_build_on 40 | end 41 | end 42 | 43 | # Build child object by dup'ing its attributes 44 | # @param item_to_duplicate [Object] Object to duplicate as new child 45 | def pbt_dup_build(item_to_duplicate, &block) 46 | self.class.pbt_dup_build(self, item_to_duplicate, &block) 47 | end 48 | 49 | # Build child object by dup'ing its attributes. Recursive for ancestry tree. 50 | # @param item_to_duplicate [Object] Object to duplicate as new child along with child ancestors 51 | def pbt_deep_dup_build(item_to_duplicate, &block) 52 | self.class.pbt_deep_dup_build(self, item_to_duplicate, &block) 53 | end 54 | 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/poly_belongs_to/faked_collection.rb: -------------------------------------------------------------------------------- 1 | module PolyBelongsTo 2 | ## 3 | # PolyBelongsTo::FakedCollection emulates an ActiveRecord::CollectionProxy of exactly one or zero items 4 | class FakedCollection 5 | # Create the Faked Colllection Proxy 6 | def initialize(obj = nil, child = nil) 7 | @obj = obj 8 | @child = child 9 | if obj.nil? || child.nil? 10 | @instance = nil 11 | else 12 | raise "Not a has_one rleationship for FakedCollection" unless PolyBelongsTo::Pbt::IsSingular[obj, child] 13 | @instance = @obj.send(PolyBelongsTo::Pbt::CollectionProxy[@obj, @child]) 14 | end 15 | self 16 | end 17 | 18 | # @return [Integer, nil] 19 | def id 20 | @instance.try(:id) 21 | end 22 | 23 | # @return [Array] 24 | def all 25 | Array[@instance].compact 26 | end 27 | 28 | # Boolean of empty? 29 | # @return [true, false] 30 | def empty? 31 | all.empty? 32 | end 33 | 34 | # Boolean of not empty? 35 | # @return [true, false] 36 | def present? 37 | !empty? 38 | end 39 | 40 | # @return [self, nil] 41 | def presence 42 | all.first ? self : nil 43 | end 44 | 45 | # Boolean of validity 46 | # @return [true, false] 47 | def valid? 48 | !!@instance.try(&:valid?) 49 | end 50 | 51 | # @return [Object, nil] 52 | def first 53 | @instance 54 | end 55 | 56 | # @return [Object, nil] 57 | def last 58 | @instance 59 | end 60 | 61 | # @return [Integer] 1 or 0 62 | def size 63 | all.size 64 | end 65 | 66 | # @return [Array] 67 | def ancestors 68 | klass.ancestors.unshift(PolyBelongsTo::FakedCollection) 69 | end 70 | 71 | # Boolean of kind match 72 | # @param thing [Object] object class 73 | # @return [true, false] 74 | def kind_of?(thing) 75 | ancestors.include? thing 76 | end 77 | 78 | # Boolean of kind match 79 | # @param thing [Object] object class 80 | # @return [true, false] 81 | def is_a?(thing) 82 | kind_of?(thing) 83 | end 84 | 85 | # alias for size 86 | # @return [Integer] 1 or 0 87 | def count 88 | size 89 | end 90 | 91 | # @return [Object] object class 92 | def klass 93 | @instance.class 94 | end 95 | 96 | # build preforms calculated build command and returns self 97 | # @param args [Array] arguments 98 | # @return [self] 99 | def build(*args) 100 | @instance = @obj.send(PolyBelongsTo::Pbt::BuildCmd[@obj, @child], *args) 101 | self 102 | end 103 | 104 | # @param args [Array] arguments 105 | # @return [Enumerator] 106 | def each(*args, &block) 107 | all.each(*args, &block) 108 | end 109 | 110 | # Returns whether this or super responds to method 111 | # @param method_name [Symbol] 112 | # @return [true, false] 113 | def respond_to?(method_name) 114 | @instance.respond_to?(method_name) || super 115 | end 116 | 117 | # Hands method and argument on to instance if it responds to method, otherwise calls super 118 | # @param method_name [Symbol] 119 | # @param args [Array] arguments 120 | # @return [true, false] 121 | def method_missing(method_name, *args, &block) 122 | if @instance.respond_to?(method_name) 123 | @instance.send method_name, *args, &block 124 | else 125 | super 126 | end 127 | end 128 | end 129 | end 130 | -------------------------------------------------------------------------------- /lib/poly_belongs_to/pbt.rb: -------------------------------------------------------------------------------- 1 | module PolyBelongsTo 2 | ## 3 | # PolyBelongsTo::Pbt is where internal methods are for implementing core and duplication methods; available on all instances. 4 | # They are available for other use if the need should arise. 5 | module Pbt 6 | # Strips date and id fields dup'd attributes 7 | # @param obj [Object] ActiveRecord instance that has attributes 8 | # @return [Hash] attributes 9 | AttrSanitizer = lambda do |obj| 10 | return {} unless obj 11 | obj.dup.attributes.delete_if do |ky, _| 12 | [:created_at, :updated_at, :deleted_at, obj.pbt_id_sym, obj.pbt_type_sym].include? ky.to_sym 13 | end 14 | end 15 | 16 | # Discerns which type of build command is used between obj and child 17 | # @param obj [Object] ActiveRecord instance to build on 18 | # @param child [Object] ActiveRecord child relation as class or instance 19 | # @return [String, nil] build command for relation, or nil 20 | BuildCmd = lambda do |obj, child| 21 | return nil unless obj && child 22 | dup_name = CollectionProxy[obj, child] 23 | if IsSingular[obj, child] 24 | "build_#{dup_name}" 25 | elsif IsPlural[obj, child] 26 | "#{dup_name}.build" 27 | end 28 | end 29 | 30 | # Returns all has_one and has_many relationships as symbols (reflect_on_all_associations) 31 | # @param obj [Object] ActiveRecord instance to reflect on 32 | # @param habtm [Object] optional boolean argument to include has_and_belongs_to_many 33 | # @return [Array] 34 | Reflects = lambda do |obj, habtm = false| 35 | return [] unless obj 36 | [:has_one, :has_many]. 37 | tap {|array| array << :has_and_belongs_to_many if habtm }. 38 | flat_map do |has| 39 | obj.class.name.constantize.reflect_on_all_associations(has).map(&:name) 40 | end 41 | end 42 | 43 | # Returns all has_one and has_many relationships as class objects (reflect_on_all_associations) 44 | # @param obj [Object] ActiveRecord instance to reflect on 45 | # @param habtm [Object] optional boolean argument to include has_and_belongs_to_many 46 | # @return [Array] 47 | ReflectsAsClasses = lambda do |obj, habtm = false| 48 | Reflects[obj, habtm].map do |ref| 49 | (obj.send(ref).try(:klass) || obj.send(ref).class).name.constantize 50 | end 51 | end 52 | 53 | # Check if the child object is a kind of child that belongs to obj 54 | # @param obj [Object] ActiveRecord instance 55 | # @param child [Object] ActiveRecord instance or model class 56 | # @return [true, false] 57 | IsReflected = lambda do |obj, child| 58 | !!CollectionProxy[obj, child] 59 | end 60 | 61 | # Plurality of object relationship (plural for has_many) 62 | # @param obj [Object] ActiveRecord instance 63 | # @param child [Object] ActiveRecord instance or model class 64 | # @return [Symbol, nil] :plural, :singular, or nil 65 | SingularOrPlural = lambda do |obj, child| 66 | return nil unless obj && child 67 | reflects = Reflects[obj] 68 | if reflects.include?(ActiveModel::Naming.singular(child).to_sym) 69 | :singular 70 | elsif CollectionProxy[obj, child] 71 | :plural 72 | end 73 | end 74 | 75 | # Singularity of object relationship (for has_one) 76 | # @param obj [Object] ActiveRecord instance 77 | # @param child [Object] ActiveRecord instance or model class 78 | # @return [true, false] 79 | IsSingular = lambda do |obj, child| 80 | SingularOrPlural[obj, child] == :singular 81 | end 82 | 83 | # Plurality of object relationship (for has_many) 84 | # @param obj [Object] ActiveRecord instance 85 | # @param child [Object] ActiveRecord instance or model class 86 | # @return [true, false] 87 | IsPlural = lambda do |obj, child| 88 | SingularOrPlural[obj, child] == :plural 89 | end 90 | 91 | # Returns the symbol of the child relation object 92 | # @param obj [Object] ActiveRecord instance 93 | # @param child [Object] ActiveRecord instance or model class 94 | # @return [Symbol] working relation on obj 95 | CollectionProxy = lambda do |obj, child| 96 | return nil unless obj && child 97 | names = [ActiveModel::Naming.singular(child).to_s, ActiveModel::Naming.plural(child).to_s].uniq 98 | Reflects[obj].detect {|ref| "#{ref}"[/(?:#{ names.join('|') }).{,3}/]} 99 | end 100 | 101 | # Returns either a ActiveRecord::CollectionProxy or a PolyBelongsTo::FakedCollection as a proxy 102 | # @param obj [Object] ActiveRecord instance 103 | # @param child [Object] ActiveRecord instance or model class 104 | # @return [Object] 105 | AsCollectionProxy = lambda do |obj, child| 106 | return PolyBelongsTo::FakedCollection.new() unless obj && child 107 | return PolyBelongsTo::FakedCollection.new(obj, child) if IsSingular[obj, child] 108 | if CollectionProxy[obj, child] 109 | obj.send(PolyBelongsTo::Pbt::CollectionProxy[obj, child]) 110 | else 111 | PolyBelongsTo::FakedCollection.new() 112 | end 113 | end 114 | end 115 | 116 | end 117 | -------------------------------------------------------------------------------- /lib/poly_belongs_to/singleton_set.rb: -------------------------------------------------------------------------------- 1 | require 'set' 2 | module PolyBelongsTo 3 | ## 4 | # PolyBelongsTo::SingletonSet is a modified instance of Set for maintaining singletons of ActiveRecord objects during any recursive flow. 5 | class SingletonSet 6 | # Creates two internal Sets 7 | # @return [self] 8 | def initialize 9 | @set = Set.new 10 | @flagged = Set.new 11 | self 12 | end 13 | 14 | # Takes ActiveRecord object and returns string of class name and object id 15 | # @param record [Object] ActiveRecord object instance 16 | # @return [String] 17 | def formatted_name(record) 18 | "#{record.class.name}-#{record.id}" 19 | end 20 | 21 | # Add record to set. Flag if covered already. 22 | # @param record [Object] ActiveRecord object instance 23 | # @return [Object, nil] Object if added safely, nil otherwise 24 | def add?(record) 25 | result = @set.add?( formatted_name( record ) ) 26 | return result if result 27 | flag(record) 28 | result 29 | end 30 | 31 | # Boolean of record inclusion 32 | # @param record [Object] ActiveRecord object instance 33 | # @return [true, false] 34 | def include?(record) 35 | return nil unless record 36 | @set.include?(formatted_name(record)) 37 | end 38 | 39 | # Add record to flagged Set list 40 | # @param record [Object] ActiveRecord object instance 41 | # @return [Set] 42 | def flag(record) 43 | @flagged << formatted_name(record) 44 | end 45 | 46 | # Boolean of record inclusion in flagged Set 47 | # @param record [Object] ActiveRecord object instance 48 | # @return [true, false] 49 | def flagged?(record) 50 | return nil unless record 51 | @flagged.include?(formatted_name(record)) 52 | end 53 | 54 | # method_missing will transform any record argument into a formatted string and pass the 55 | # method and arguments on to the internal Set. Also will flag any existing records covered. 56 | def method_missing(mthd, *args, &block) 57 | new_recs = args.reduce([]) {|a, i| a.push(formatted_name(i)) if i.class.ancestors.include?(ActiveRecord::Base); a} 58 | result = @set.send(mthd, 59 | *(args.map do |arg| 60 | arg.class.ancestors.include?(ActiveRecord::Base) ? formatted_name(arg) : arg 61 | end 62 | ), 63 | &block 64 | ) 65 | @set.to_a.select {|i| new_recs.include? i }.each {|f| @flagged << f} 66 | result 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /lib/poly_belongs_to/sorted_reflection_decorator.rb: -------------------------------------------------------------------------------- 1 | module PolyBelongsTo 2 | module SortedReflectionDecorator 3 | def self.included(base) 4 | base.module_exec do 5 | original_method = instance_method(:reflect_on_all_associations) 6 | define_method(:reflect_on_all_associations) do |*args, &block| 7 | original_method.bind(self).call(*args, &block).sort_by {|a| a.polymorphic? ? 0 : 1 } 8 | end 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/poly_belongs_to/version.rb: -------------------------------------------------------------------------------- 1 | module PolyBelongsTo 2 | # VERSION follows symantic versioning rules 3 | VERSION = "1.0.1" 4 | end 5 | -------------------------------------------------------------------------------- /poly_belongs_to.gemspec: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.push File.expand_path("../lib", __FILE__) 2 | 3 | # Maintain your gem's version: 4 | require "poly_belongs_to/version" 5 | 6 | # Describe your gem and declare its dependencies: 7 | Gem::Specification.new do |s| 8 | s.name = "poly_belongs_to" 9 | s.version = PolyBelongsTo::VERSION 10 | s.authors = ["Daniel P. Clark"] 11 | s.email = ["6ftdan@gmail.com"] 12 | s.homepage = "https://github.com/danielpclark/PolyBelongsTo" 13 | s.summary = "Uniform Omni-Relational ActiveRecord Tools" 14 | s.description = "Uniform Omni-Relational ActiveRecord Tools. Includes polymorphic and any belongs_to relation." 15 | s.license = "MIT" 16 | 17 | s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] 18 | 19 | s.required_ruby_version = ">= 1.9.3" 20 | 21 | s.add_dependency "rails", [">= 3.1", "< 6"] 22 | 23 | s.add_development_dependency "sqlite3", "~> 1.3" 24 | s.add_development_dependency "minitest-rails", [">= 0.9", "< 3"] 25 | s.add_development_dependency "minitest-reporters", [">= 0.7.1", "< 2"] 26 | end 27 | -------------------------------------------------------------------------------- /test/core_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | require 'minitest/autorun' 3 | 4 | class CoreTest < ActiveSupport::TestCase 5 | fixtures :all 6 | 7 | describe PolyBelongsTo::Core do 8 | 9 | it "is a module" do 10 | PolyBelongsTo::Core.must_be_kind_of Module 11 | end 12 | 13 | it "#poly? User as not polymorphic" do 14 | user = users(:bob) 15 | user.wont_be :poly? 16 | User.wont_be :poly? 17 | end 18 | 19 | it "#poly? Tag as not polymorphic" do 20 | tag = tags(:bob_tag) 21 | tag.wont_be :poly? 22 | Tag.wont_be :poly? 23 | end 24 | 25 | it "#poly? Phone as polymorphic" do 26 | phone = phones(:bob_phone) 27 | phone.must_be :poly? 28 | Phone.must_be :poly? 29 | end 30 | 31 | it "#pbt User belongs to table as nil" do 32 | user = users(:bob) 33 | user.pbt.must_be_nil 34 | User.pbt.must_be_nil 35 | end 36 | 37 | it "#pbt Tag belongs to table as :user" do 38 | tag = tags(:bob_tag) 39 | tag.pbt.must_be_same_as :user 40 | Tag.pbt.must_be_same_as :user 41 | end 42 | 43 | it "#pbt Phone belongs to table as :phoneable" do 44 | phone = phones(:bob_phone) 45 | phone.pbt.must_be_same_as :phoneable 46 | Phone.pbt.must_be_same_as :phoneable 47 | end 48 | 49 | it "#has_one_of" do 50 | Profile.has_one_of.must_equal [:photo] 51 | end 52 | 53 | it "#has_many_of" do 54 | Profile.has_many_of.must_equal [:phones, :addresses] 55 | HmtAssembly.has_many_of.must_equal [:manifests, :hmt_parts] 56 | HmtPart.has_many_of.must_equal [:manifests, :hmt_assemblies] 57 | end 58 | 59 | it "#habtm_of" do 60 | Assembly.habtm_of.must_equal [:parts] 61 | Part.habtm_of.must_equal [:assemblies] 62 | end 63 | 64 | it "#pbts multiple parents" do 65 | tire = tires(:low_profile1) 66 | parents = tire.class.pbts 67 | parents.must_be_kind_of Array 68 | parents.must_include :user 69 | parents.must_include :car 70 | parents = tire.pbts 71 | parents.must_be_kind_of Array 72 | parents.must_include :user 73 | parents.must_include :car 74 | end 75 | 76 | it "#pbt_params_name User params name as :user" do 77 | user = users(:bob) 78 | user.pbt_params_name.must_be_same_as :user 79 | User.pbt_params_name.must_be_same_as :user 80 | User.pbt_params_name(true).must_be_same_as :user 81 | User.pbt_params_name(false).must_be_same_as :user 82 | end 83 | 84 | it "#pbt_params_name Tag params name as :tag" do 85 | tag = tags(:bob_tag) 86 | tag.pbt_params_name.must_be_same_as :tag 87 | Tag.pbt_params_name.must_be_same_as :tag 88 | Tag.pbt_params_name(true).must_be_same_as :tag 89 | Tag.pbt_params_name(false).must_be_same_as :tag 90 | end 91 | 92 | it "#pbt_params_name Phone params name as :phones_attributes" do 93 | phone = phones(:bob_phone) 94 | phone.pbt_params_name.must_be_same_as :phones_attributes 95 | Phone.pbt_params_name.must_be_same_as :phones_attributes 96 | Phone.pbt_params_name(true).must_be_same_as :phones_attributes 97 | end 98 | 99 | it "#pbt_params_name Phone params name with false as :phone" do 100 | phone = phones(:bob_phone) 101 | phone.pbt_params_name(false).must_be_same_as :phone 102 | Phone.pbt_params_name(false).must_be_same_as :phone 103 | end 104 | 105 | it "#pbt_id_sym User belongs to field id symbol as nil" do 106 | user = users(:bob) 107 | user.pbt_id_sym.must_be_nil 108 | User.pbt_id_sym.must_be_nil 109 | end 110 | 111 | it "#pbt_id_sym Tag belongs to field id symbol as :tag_id" do 112 | tag = tags(:bob_tag) 113 | tag.pbt_id_sym.must_be_same_as :user_id 114 | Tag.pbt_id_sym.must_be_same_as :user_id 115 | end 116 | 117 | it "#pbt_id_sym Phone belongs to field id symbol as :phoneable_id" do 118 | phone = phones(:bob_phone) 119 | phone.pbt_id_sym.must_be_same_as :phoneable_id 120 | Phone.pbt_id_sym.must_be_same_as :phoneable_id 121 | end 122 | 123 | it "#pbt_type_sym User belongs to field type symbol as nil" do 124 | user = users(:bob) 125 | user.pbt_type_sym.must_be_nil 126 | User.pbt_type_sym.must_be_nil 127 | end 128 | 129 | it "#pbt_type_sym Tag belongs to field type symbol as nil" do 130 | tag = tags(:bob_tag) 131 | tag.pbt_type_sym.must_be_nil 132 | Tag.pbt_type_sym.must_be_nil 133 | end 134 | 135 | it "#pbt_type_sym Phone belongs to field type symbol as :phoneable_type" do 136 | phone = phones(:bob_phone) 137 | phone.pbt_type_sym.must_be_same_as :phoneable_type 138 | Phone.pbt_type_sym.must_be_same_as :phoneable_type 139 | end 140 | 141 | it "#pbt_id User belongs to id as nil" do 142 | user = users(:bob) 143 | user.pbt_id.must_be_nil 144 | end 145 | 146 | it "#pbt_id Tag belongs to id as user's id" do 147 | tag = tags(:bob_tag) 148 | tag.pbt_id.must_be_same_as ActiveRecord::FixtureSet.identify(:bob) 149 | end 150 | 151 | it "#pbt_id Phone belongs to id as user's profile id" do 152 | phone = phones(:bob_phone) 153 | phone.pbt_id.must_be_same_as ActiveRecord::FixtureSet.identify(:bob_prof) 154 | end 155 | 156 | it "#pbt_type User belongs to type as nil" do 157 | user = users(:bob) 158 | user.pbt_type.must_be_nil 159 | end 160 | 161 | it "#pbt_type Tag belongs to type as nil" do 162 | tag = tags(:bob_tag) 163 | tag.pbt_type.must_be_nil 164 | end 165 | 166 | it "#pbt_type Phone belongs to type as 'Profile'" do 167 | phone = phones(:bob_phone) 168 | phone.pbt_type.must_equal "Profile" 169 | end 170 | 171 | it "#pbt_parent User parent returns nil" do 172 | user = users(:bob) 173 | user.pbt_parent.must_be_nil 174 | end 175 | 176 | it "#pbt_parent Tag parent returns user instance" do 177 | user = users(:bob) 178 | tag = user.tags.build 179 | tag.pbt_parent.id.must_be_same_as user.id 180 | end 181 | 182 | it "#pbt_parent Phone parent returns profile" do 183 | user = users(:bob) 184 | profile = user.profiles.build 185 | phone = profile.phones.build 186 | profile.save 187 | phone.pbt_parent.id.must_be_same_as profile.id 188 | end 189 | 190 | it "#pbt_parent Profile parent returns user" do 191 | user = users(:bob) 192 | profile = user.profiles.build 193 | profile.save 194 | profile.pbt_parent.id.must_be_same_as user.id 195 | end 196 | 197 | it "#pbt_parent returns nil if no ID is set for parent relationship" do 198 | alpha = Alpha.new; alpha.save 199 | beta = alpha.betas.build; beta.save 200 | alpha.pbt_parent.must_be_nil 201 | beta.pbt_parent.wont_be_nil 202 | beta.pbt_parent.must_equal alpha 203 | squishy = Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Address") 204 | squishy.pbt_parent.must_be_nil 205 | end 206 | 207 | it "#pbt_top_parent climbs up belongs_to hierarchy to the top; polymorphic relationships first" do 208 | alpha = Alpha.new; alpha.save 209 | beta = alpha.betas.build; beta.save 210 | capa = beta.capas.build; capa.save 211 | delta = capa.deltas.build; delta.save 212 | delta.pbt_top_parent.must_equal alpha 213 | end 214 | 215 | it "#pbt_top_parent with circular relation goes till the repeat" do 216 | alpha = Alpha.new; alpha.save 217 | beta = alpha.betas.build; beta.save 218 | capa = beta.capas.build; capa.save 219 | delta = capa.deltas.build; delta.save 220 | alpha.update(delta_id: delta.id) 221 | delta.pbt_top_parent.must_equal alpha 222 | alpha.pbt_top_parent.must_equal beta 223 | beta. pbt_top_parent.must_equal capa 224 | capa. pbt_top_parent.must_equal delta 225 | end 226 | 227 | it "#pbt_parents can show multiple parents" do 228 | user = User.new(id: 1) 229 | user.cars.build 230 | user.cars.first.tires.build(user_id: user.id) 231 | user.save 232 | parents = user.cars.first.tires.first.pbt_parents 233 | parents.must_be_kind_of Array 234 | parents.must_include user 235 | parents.must_include user.cars.first 236 | user.destroy 237 | end 238 | 239 | it "#pbt_parents one parent for polymorphic" do 240 | bob_address = addresses(:bob_address) 241 | parents = bob_address.pbt_parents 242 | parents.must_be_kind_of Array 243 | parents.size.must_equal 1 244 | parents.first.must_equal profiles(:bob_prof) 245 | end 246 | 247 | it "#pbt_orphans returns all parentless records for current Object" do 248 | obj = Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Phone") 249 | Squishy.pbt_orphans.to_a.must_equal [obj] 250 | obj2 = Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Address") 251 | Squishy.pbt_orphans.to_a.sort.must_equal [obj, obj2].sort 252 | obj3 = Beta.create(Beta.pbt_id_sym => 12_345) 253 | Beta.pbt_orphans.to_a.must_equal [obj3] 254 | end 255 | 256 | it "#pbt_orphans returns nil for non parent type records" do 257 | User.create() 258 | User.pbt_orphans.must_be_nil 259 | end 260 | 261 | it "#pbt_orphans ignores mislabled record types" do 262 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Object") 263 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Class") 264 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Squishable") 265 | Squishy.pbt_orphans.must_be :empty? 266 | end 267 | 268 | it "#pbt_mistypes returns strings of mislabled polymorphic record types" do 269 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Object") 270 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Class") 271 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Squishable") 272 | Squishy.pbt_mistypes.to_a.sort.must_equal ["Object", "Class", "Squishable"].sort 273 | end 274 | 275 | it "#pbt_mistyped returns mislabled polymorphic record types" do 276 | obj = Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Object") 277 | obj2 = Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Class") 278 | obj3 = Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Squishable") 279 | Squishy.pbt_mistyped.to_a.sort.must_equal [obj, obj2, obj3].sort 280 | end 281 | 282 | it "#pbt_valid_types returns strings of valid polymorphic record types" do 283 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Object") 284 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Class") 285 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Squishable") 286 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Phone") 287 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Address") 288 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "GeoLocation") 289 | Squishy.pbt_valid_types.sort.must_equal ["Phone", "Address", "GeoLocation"].sort 290 | end 291 | 292 | it "#pbt_valid_types returns empty Array for no valid record types" do 293 | Coffee.create(Coffee.pbt_id_sym => 12_345, Coffee.pbt_type_sym => "Object") 294 | Coffee.create(Coffee.pbt_id_sym => 12_345, Coffee.pbt_type_sym => "Class") 295 | Coffee.create(Coffee.pbt_id_sym => 12_345, Coffee.pbt_type_sym => "Squishable") 296 | Coffee.pbt_valid_types.to_a.sort.must_be :empty? 297 | end 298 | 299 | it "I'm just curious if polymorphic can belong to itself" do 300 | coffee = Coffee.create(Coffee.pbt_id_sym => 12_345, Coffee.pbt_type_sym => "Coffee") 301 | coffee.must_be :valid? 302 | coffee.coffeeable_type.must_equal "Coffee" 303 | coffee.must_be :persisted? 304 | end 305 | 306 | it "#pbt_mistyped returns empty Array for no valid record types" do 307 | Coffee.create(Coffee.pbt_id_sym => 12_345, Coffee.pbt_type_sym => "Phone") 308 | Coffee.create(Coffee.pbt_id_sym => 12_345, Coffee.pbt_type_sym => "Address") 309 | Coffee.create(Coffee.pbt_id_sym => 12_345, Coffee.pbt_type_sym => "User") 310 | Coffee.pbt_mistyped.to_a.sort.must_be :empty? 311 | end 312 | 313 | it "#pbt_mistypes returns empty Array if only valid polymorphic record types exist" do 314 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Phone") 315 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Address") 316 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "GeoLocation") 317 | Squishy.pbt_mistypes.sort.must_be :empty? 318 | end 319 | 320 | it "#pbt_poly_types returns strings of all polymorphic record types" do 321 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Object") 322 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Class") 323 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Squishable") 324 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Phone") 325 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Address") 326 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "GeoLocation") 327 | Squishy.pbt_poly_types.sort.must_equal ["Phone", "Address", "GeoLocation", "Object", "Class", "Squishable"].sort 328 | end 329 | 330 | it "keeps helper methods private" do 331 | Squishy.singleton_class.private_method_defined?(:_pbt_polymorphic_orphans).must_be_same_as true 332 | Squishy.singleton_class.method_defined?(:_pbt_polymorphic_orphans).must_be_same_as false 333 | Squishy.method_defined?(:_pbt_polymorphic_orphans).must_be_same_as false 334 | Squishy.singleton_class.private_method_defined?(:_pbt_nonpolymorphic_orphans).must_be_same_as true 335 | Squishy.singleton_class.method_defined?(:_pbt_nonpolymorphic_orphans).must_be_same_as false 336 | Squishy.method_defined?(:_pbt_nonpolymorphic_orphans).must_be_same_as false 337 | end 338 | 339 | it "#orphan? gives boolean if record is orphaned" do 340 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Phone").must_be :orphan? 341 | Squishy.create(Squishy.pbt_id_sym => 12_345, Squishy.pbt_type_sym => "Address").must_be :orphan? 342 | User.create().wont_be :orphan? 343 | user = users(:bob) 344 | profile = user.profiles.build 345 | phone = profile.phones.build 346 | profile.save 347 | profile.wont_be :orphan? 348 | phone.wont_be :orphan? 349 | user.wont_be :orphan? 350 | Alpha.create.must_be :orphan? 351 | end 352 | 353 | describe "works with camelcase realtions" do 354 | it "pbt_parent snakecase to camelcase" do 355 | work_order = WorkOrder.create() 356 | e = Event.create(work_order: work_order) 357 | _(e.pbt_parent).must_equal work_order 358 | end 359 | 360 | it "pbt_parents snakecase to camelcase" do 361 | work_order = WorkOrder.create() 362 | e = Event.create(work_order: work_order) 363 | _(e.pbt_parents).must_include work_order 364 | end 365 | 366 | it "pbt_orphans snakecase to camelcase" do 367 | e = Event.create(work_order_id: 15) 368 | WorkOrder.destroy_all 369 | _(Event.pbt_orphans.pluck(:work_order_id).first).must_equal e.work_order_id 370 | end 371 | end 372 | end 373 | end 374 | -------------------------------------------------------------------------------- /test/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | DummyApp.load_tasks 7 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | end 6 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielpclark/PolyBelongsTo/38d51d37f9148613519d6b6d56bdf4d0884f0e86/test/dummy/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /test/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /test/dummy/app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielpclark/PolyBelongsTo/38d51d37f9148613519d6b6d56bdf4d0884f0e86/test/dummy/app/mailers/.keep -------------------------------------------------------------------------------- /test/dummy/app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielpclark/PolyBelongsTo/38d51d37f9148613519d6b6d56bdf4d0884f0e86/test/dummy/app/models/.keep -------------------------------------------------------------------------------- /test/dummy/app/models/address.rb: -------------------------------------------------------------------------------- 1 | class Address < ActiveRecord::Base 2 | belongs_to :addressable, polymorphic: true 3 | has_one :geo_location 4 | has_many :squishies, as: :squishable, dependent: :destroy 5 | end 6 | -------------------------------------------------------------------------------- /test/dummy/app/models/address_book.rb: -------------------------------------------------------------------------------- 1 | class AddressBook < ActiveRecord::Base 2 | has_many :contacts, as: :contactable, dependent: :destroy 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/alpha.rb: -------------------------------------------------------------------------------- 1 | class Alpha < ActiveRecord::Base 2 | belongs_to :delta 3 | has_many :betas 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/assembly.rb: -------------------------------------------------------------------------------- 1 | class Assembly < ActiveRecord::Base 2 | has_and_belongs_to_many :parts 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/beta.rb: -------------------------------------------------------------------------------- 1 | class Beta < ActiveRecord::Base 2 | belongs_to :alpha 3 | has_many :capas 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/big_company.rb: -------------------------------------------------------------------------------- 1 | class BigCompany < ActiveRecord::Base 2 | has_many :work_orders 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/capa.rb: -------------------------------------------------------------------------------- 1 | class Capa < ActiveRecord::Base 2 | belongs_to :beta 3 | has_many :deltas 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/car.rb: -------------------------------------------------------------------------------- 1 | class Car < ActiveRecord::Base 2 | belongs_to :user 3 | has_many :tires, dependent: :destroy 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/coffee.rb: -------------------------------------------------------------------------------- 1 | class Coffee < ActiveRecord::Base 2 | belongs_to :coffeeable, polymorphic: true 3 | has_many :coffees, as: :coffeeable, dependent: :destroy 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielpclark/PolyBelongsTo/38d51d37f9148613519d6b6d56bdf4d0884f0e86/test/dummy/app/models/concerns/.keep -------------------------------------------------------------------------------- /test/dummy/app/models/contact.rb: -------------------------------------------------------------------------------- 1 | class Contact < ActiveRecord::Base 2 | belongs_to :user 3 | belongs_to :contactable, polymorphic: true 4 | has_one :profile, as: :profileable, dependent: :destroy 5 | accepts_nested_attributes_for :profile 6 | end 7 | -------------------------------------------------------------------------------- /test/dummy/app/models/delta.rb: -------------------------------------------------------------------------------- 1 | class Delta < ActiveRecord::Base 2 | belongs_to :capa 3 | has_many :alphas 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/event.rb: -------------------------------------------------------------------------------- 1 | class Event < ActiveRecord::Base 2 | belongs_to :work_order 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/geo_location.rb: -------------------------------------------------------------------------------- 1 | class GeoLocation < ActiveRecord::Base 2 | belongs_to :address 3 | has_many :squishies, as: :squishable, dependent: :destroy 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/hmt_assembly.rb: -------------------------------------------------------------------------------- 1 | class HmtAssembly < ActiveRecord::Base 2 | has_many :manifests 3 | has_many :hmt_parts, through: :manifests 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/hmt_part.rb: -------------------------------------------------------------------------------- 1 | class HmtPart < ActiveRecord::Base 2 | has_many :manifests 3 | has_many :hmt_assemblies, through: :manifests 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/manifest.rb: -------------------------------------------------------------------------------- 1 | class Manifest < ApplicationRecord 2 | belongs_to :hmt_assembly 3 | belongs_to :hmt_part 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/part.rb: -------------------------------------------------------------------------------- 1 | class Part < ActiveRecord::Base 2 | has_and_belongs_to_many :assemblies 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/phone.rb: -------------------------------------------------------------------------------- 1 | class Phone < ActiveRecord::Base 2 | belongs_to :phoneable, polymorphic: true 3 | has_one :squishy, as: :squishable, dependent: :destroy 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/photo.rb: -------------------------------------------------------------------------------- 1 | class Photo < ActiveRecord::Base 2 | belongs_to :photoable, polymorphic: true 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/profile.rb: -------------------------------------------------------------------------------- 1 | class Profile < ActiveRecord::Base 2 | belongs_to :profileable, polymorphic: true 3 | has_many :phones, as: :phoneable, dependent: :destroy 4 | has_many :addresses, as: :addressable, dependent: :destroy 5 | has_one :photo, as: :photoable, dependent: :destroy 6 | accepts_nested_attributes_for :phones, :addresses, :photo 7 | end 8 | -------------------------------------------------------------------------------- /test/dummy/app/models/squishy.rb: -------------------------------------------------------------------------------- 1 | class Squishy < ActiveRecord::Base 2 | belongs_to :squishable, polymorphic: true 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/ssn.rb: -------------------------------------------------------------------------------- 1 | class Ssn < ActiveRecord::Base 2 | belongs_to :user 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/tag.rb: -------------------------------------------------------------------------------- 1 | class Tag < ActiveRecord::Base 2 | belongs_to :user 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/tire.rb: -------------------------------------------------------------------------------- 1 | class Tire < ActiveRecord::Base 2 | belongs_to :user 3 | belongs_to :car 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | has_one :ssn, dependent: :destroy 3 | has_many :tags, dependent: :destroy 4 | has_many :contacts, dependent: :destroy 5 | has_many :profiles, as: :profileable, dependent: :destroy 6 | has_many :cars, dependent: :destroy 7 | has_many :tires, dependent: :destroy 8 | end 9 | -------------------------------------------------------------------------------- /test/dummy/app/models/work_order.rb: -------------------------------------------------------------------------------- 1 | class WorkOrder < ActiveRecord::Base 2 | has_many :events, dependent: :destroy 3 | belongs_to :big_company 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/dummy/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /test/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /test/dummy/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /test/dummy/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | 4 | # path to your application root. 5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 6 | 7 | Dir.chdir APP_ROOT do 8 | # This script is a starting point to setup your application. 9 | # Add necessary setup steps to this file: 10 | 11 | puts "== Installing dependencies ==" 12 | system "gem install bundler --conservative" 13 | system "bundle check || bundle install" 14 | 15 | # puts "\n== Copying sample files ==" 16 | # unless File.exist?("config/database.yml") 17 | # system "cp config/database.yml.sample config/database.yml" 18 | # end 19 | 20 | puts "\n== Preparing database ==" 21 | system "bin/rake db:setup" 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system "rm -f log/*" 25 | system "rm -rf tmp/cache" 26 | 27 | puts "\n== Restarting application server ==" 28 | system "touch tmp/restart.txt" 29 | end 30 | -------------------------------------------------------------------------------- /test/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run DummyApp 5 | -------------------------------------------------------------------------------- /test/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require(*Rails.groups) 6 | require "poly_belongs_to" 7 | 8 | module Dummy 9 | class Application < Rails::Application 10 | # Settings in config/environments/* take precedence over those specified here. 11 | # Application configuration should go into files in config/initializers 12 | # -- all .rb files in that directory are automatically loaded. 13 | 14 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 15 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 16 | # config.time_zone = 'Central Time (US & Canada)' 17 | 18 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 19 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 20 | # config.i18n.default_locale = :de 21 | 22 | # Do not swallow errors in after_commit/after_rollback callbacks. 23 | if Rails.version =~ /^(?:(?:4\.[2-9])|[5-9])/ 24 | config.active_record.raise_in_transactional_callbacks = true 25 | end 26 | end 27 | end 28 | 29 | DummyApp = begin 30 | if ::Rails.version.to_s =~ /^(?:(?:4\.[2-9])|[5-9])/ 31 | Rails.application 32 | else 33 | Dummy::Application 34 | end 35 | end 36 | 37 | -------------------------------------------------------------------------------- /test/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) 6 | 7 | -------------------------------------------------------------------------------- /test/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /test/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the DummyApp. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the DummyApp. 5 | DummyApp.initialize! 6 | -------------------------------------------------------------------------------- /test/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | DummyApp.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations. 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | 30 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 31 | # yet still be able to expire them through the digest params. 32 | config.assets.digest = true 33 | 34 | # Adds additional error checking when serving assets at runtime. 35 | # Checks for improperly declared sprockets dependencies. 36 | # Raises helpful error messages. 37 | config.assets.raise_runtime_errors = true 38 | 39 | # Raises error for missing translations 40 | # config.action_view.raise_on_missing_translations = true 41 | end 42 | -------------------------------------------------------------------------------- /test/dummy/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | DummyApp.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like 20 | # NGINX, varnish or squid. 21 | # config.action_dispatch.rack_cache = true 22 | 23 | # Disable serving static files from the `/public` folder by default since 24 | # Apache or NGINX already handles this. 25 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? 26 | 27 | # Compress JavaScripts and CSS. 28 | config.assets.js_compressor = :uglifier 29 | # config.assets.css_compressor = :sass 30 | 31 | # Do not fallback to assets pipeline if a precompiled asset is missed. 32 | config.assets.compile = false 33 | 34 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 35 | # yet still be able to expire them through the digest params. 36 | config.assets.digest = true 37 | 38 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 39 | 40 | # Specifies the header that your server uses for sending files. 41 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 42 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 43 | 44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 45 | # config.force_ssl = true 46 | 47 | # Use the lowest log level to ensure availability of diagnostic information 48 | # when problems arise. 49 | config.log_level = :debug 50 | 51 | # Prepend all log lines with the following tags. 52 | # config.log_tags = [ :subdomain, :uuid ] 53 | 54 | # Use a different logger for distributed setups. 55 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 56 | 57 | # Use a different cache store in production. 58 | # config.cache_store = :mem_cache_store 59 | 60 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 61 | # config.action_controller.asset_host = 'http://assets.example.com' 62 | 63 | # Ignore bad email addresses and do not raise email delivery errors. 64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 65 | # config.action_mailer.raise_delivery_errors = false 66 | 67 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 68 | # the I18n.default_locale when a translation cannot be found). 69 | config.i18n.fallbacks = true 70 | 71 | # Send deprecation notices to registered listeners. 72 | config.active_support.deprecation = :notify 73 | 74 | # Use default logging formatter so that PID and timestamp are not suppressed. 75 | config.log_formatter = ::Logger::Formatter.new 76 | 77 | # Do not dump schema after migrations. 78 | config.active_record.dump_schema_after_migration = false 79 | end 80 | -------------------------------------------------------------------------------- /test/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | DummyApp.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static file server for tests with Cache-Control for performance. 16 | config.serve_static_files = true 17 | config.static_cache_control = 'public, max-age=3600' 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Randomize the order test cases are executed. 35 | config.active_support.test_order = :random 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | DummyApp.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # DummyApp.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # DummyApp.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | DummyApp.config.action_dispatch.cookies_serializer = :json 4 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | DummyApp.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | DummyApp.config.session_store :cookie_store, key: '_dummy_session' 4 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /test/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /test/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | DummyApp.routes.draw do 2 | # The priority is based upon order of creation: first created -> highest priority. 3 | # See how all your routes lay out with "rake routes". 4 | 5 | # You can have the root of your site routed with "root" 6 | # root 'welcome#index' 7 | 8 | # Example of regular route: 9 | # get 'products/:id' => 'catalog#view' 10 | 11 | # Example of named route that can be invoked with purchase_url(id: product.id) 12 | # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase 13 | 14 | # Example resource route (maps HTTP verbs to controller actions automatically): 15 | # resources :products 16 | 17 | # Example resource route with options: 18 | # resources :products do 19 | # member do 20 | # get 'short' 21 | # post 'toggle' 22 | # end 23 | # 24 | # collection do 25 | # get 'sold' 26 | # end 27 | # end 28 | 29 | # Example resource route with sub-resources: 30 | # resources :products do 31 | # resources :comments, :sales 32 | # resource :seller 33 | # end 34 | 35 | # Example resource route with more complex sub-resources: 36 | # resources :products do 37 | # resources :comments 38 | # resources :sales do 39 | # get 'recent', on: :collection 40 | # end 41 | # end 42 | 43 | # Example resource route with concerns: 44 | # concern :toggleable do 45 | # post 'toggle' 46 | # end 47 | # resources :posts, concerns: :toggleable 48 | # resources :photos, concerns: :toggleable 49 | 50 | # Example resource route within a namespace: 51 | # namespace :admin do 52 | # # Directs /admin/products/* to Admin::ProductsController 53 | # # (app/controllers/admin/products_controller.rb) 54 | # resources :products 55 | # end 56 | end 57 | -------------------------------------------------------------------------------- /test/dummy/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: 5a0d0636932395ba944bad79566a2882ef6bfccacdb20fbd6cdee02dcd8fd425cd540c76957725abe5c6a0ea401dc62051b7726883634676179a1d3f774c53ba 15 | 16 | test: 17 | secret_key_base: 75feeeabfc7d15bb7ad0286913c29e8282158207da6f916e6e59d8f7b97616c2711c7f3841f72d3334a1c8eed2f25ab9228ac81631e5b370bdf99cbbbad5a585 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150211224139_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration 2 | def change 3 | create_table :users do |t| 4 | t.string :content 5 | 6 | t.timestamps null: false 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150211224157_create_tags.rb: -------------------------------------------------------------------------------- 1 | class CreateTags < ActiveRecord::Migration 2 | def change 3 | create_table :tags do |t| 4 | t.integer :user_id 5 | t.string :content 6 | 7 | t.timestamps null: false 8 | end 9 | add_index :tags, :user_id 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150211224225_create_phones.rb: -------------------------------------------------------------------------------- 1 | class CreatePhones < ActiveRecord::Migration 2 | def change 3 | create_table :phones do |t| 4 | t.references :phoneable, polymorphic: true, index: true 5 | t.string :content 6 | 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150216092218_create_addresses.rb: -------------------------------------------------------------------------------- 1 | class CreateAddresses < ActiveRecord::Migration 2 | def change 3 | create_table :addresses do |t| 4 | t.references :addressable, polymorphic: true, index: true 5 | t.string :content 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150216092338_create_profiles.rb: -------------------------------------------------------------------------------- 1 | class CreateProfiles < ActiveRecord::Migration 2 | def change 3 | create_table :profiles do |t| 4 | t.references :profileable, polymorphic: true, index: true 5 | t.string :content 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150216092411_create_photos.rb: -------------------------------------------------------------------------------- 1 | class CreatePhotos < ActiveRecord::Migration 2 | def change 3 | create_table :photos do |t| 4 | t.references :photoable, polymorphic: true, index: true 5 | t.string :content 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150216092449_create_contacts.rb: -------------------------------------------------------------------------------- 1 | class CreateContacts < ActiveRecord::Migration 2 | def change 3 | create_table :contacts do |t| 4 | t.integer :user_id 5 | t.string :content 6 | 7 | t.timestamps 8 | end 9 | add_index :contacts, :user_id 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150216092519_create_ssns.rb: -------------------------------------------------------------------------------- 1 | class CreateSsns < ActiveRecord::Migration 2 | def change 3 | create_table :ssns do |t| 4 | t.integer :user_id 5 | t.string :content 6 | 7 | t.timestamps 8 | end 9 | add_index :ssns, :user_id 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150220213422_create_geo_locations.rb: -------------------------------------------------------------------------------- 1 | class CreateGeoLocations < ActiveRecord::Migration 2 | def change 3 | create_table :geo_locations do |t| 4 | t.integer :address_id 5 | t.string :content 6 | 7 | t.timestamps 8 | end 9 | add_index :geo_locations, :address_id 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150220230146_create_squishies.rb: -------------------------------------------------------------------------------- 1 | class CreateSquishies < ActiveRecord::Migration 2 | def change 3 | create_table :squishies do |t| 4 | t.string :content 5 | t.references :squishable, polymorphic: true, index: true 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150301100658_create_tires.rb: -------------------------------------------------------------------------------- 1 | class CreateTires < ActiveRecord::Migration 2 | def change 3 | create_table :tires do |t| 4 | t.references :user, index: true 5 | t.references :car, index: true 6 | t.string :content 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150301100722_create_cars.rb: -------------------------------------------------------------------------------- 1 | class CreateCars < ActiveRecord::Migration 2 | def change 3 | create_table :cars do |t| 4 | t.references :user, index: true 5 | t.string :content 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150322233720_create_alphas.rb: -------------------------------------------------------------------------------- 1 | class CreateAlphas < ActiveRecord::Migration 2 | def change 3 | create_table :alphas do |t| 4 | t.string :content 5 | t.references :delta, index: true 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150322233733_create_beta.rb: -------------------------------------------------------------------------------- 1 | class CreateBeta < ActiveRecord::Migration 2 | def change 3 | create_table :beta do |t| 4 | t.string :content 5 | t.references :alpha, index: true 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150322233743_create_capas.rb: -------------------------------------------------------------------------------- 1 | class CreateCapas < ActiveRecord::Migration 2 | def change 3 | create_table :capas do |t| 4 | t.string :content 5 | t.references :beta, index: true 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150322233755_create_delta.rb: -------------------------------------------------------------------------------- 1 | class CreateDelta < ActiveRecord::Migration 2 | def change 3 | create_table :delta do |t| 4 | t.string :content 5 | t.references :capa, index: true 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20150511161648_create_coffees.rb: -------------------------------------------------------------------------------- 1 | class CreateCoffees < ActiveRecord::Migration 2 | def change 3 | create_table :coffees do |t| 4 | t.references :coffeeable, polymorphic: true, index: true 5 | 6 | t.timestamps null: false 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20160120224015_add_contactable_to_contacts.rb: -------------------------------------------------------------------------------- 1 | class AddContactableToContacts < ActiveRecord::Migration 2 | def change 3 | add_reference :contacts, :contactable, polymorphic: true, index: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20160120231645_create_address_books.rb: -------------------------------------------------------------------------------- 1 | class CreateAddressBooks < ActiveRecord::Migration 2 | def change 3 | create_table :address_books do |t| 4 | 5 | t.timestamps null: false 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20161209115003_create_events.rb: -------------------------------------------------------------------------------- 1 | class CreateEvents < ActiveRecord::Migration 2 | def change 3 | create_table :events do |t| 4 | t.integer :work_order_id 5 | 6 | t.timestamps null: false 7 | end 8 | add_index :events, :work_order_id 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20161209115212_create_work_orders.rb: -------------------------------------------------------------------------------- 1 | class CreateWorkOrders < ActiveRecord::Migration 2 | def change 3 | create_table :work_orders do |t| 4 | 5 | t.timestamps null: false 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20161210074545_create_big_companies.rb: -------------------------------------------------------------------------------- 1 | class CreateBigCompanies < ActiveRecord::Migration 2 | def change 3 | create_table :big_companies do |t| 4 | 5 | t.timestamps null: false 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20161210074616_add_big_company_id_to_work_order.rb: -------------------------------------------------------------------------------- 1 | class AddBigCompanyIdToWorkOrder < ActiveRecord::Migration 2 | def change 3 | add_column :work_orders, :big_company_id, :integer 4 | add_index :work_orders, :big_company_id 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20161210145334_create_assemblies.rb: -------------------------------------------------------------------------------- 1 | class CreateAssemblies < ActiveRecord::Migration 2 | def change 3 | create_table :assemblies do |t| 4 | 5 | t.timestamps null: false 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20161210145355_create_parts.rb: -------------------------------------------------------------------------------- 1 | class CreateParts < ActiveRecord::Migration 2 | def change 3 | create_table :parts do |t| 4 | 5 | t.timestamps null: false 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20161210145757_create_assembly_part_join_table.rb: -------------------------------------------------------------------------------- 1 | class CreateAssemblyPartJoinTable < ActiveRecord::Migration 2 | def change 3 | create_join_table :assemblies, :parts do |t| 4 | t.index [:assembly_id, :part_id] 5 | t.index [:part_id, :assembly_id] 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20161210150330_create_hmt_assemblies.rb: -------------------------------------------------------------------------------- 1 | class CreateHmtAssemblies < ActiveRecord::Migration 2 | def change 3 | create_table :hmt_assemblies do |t| 4 | 5 | t.timestamps null: false 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/dummy/db/migrate/20161210150343_create_hmt_parts.rb: -------------------------------------------------------------------------------- 1 | class CreateHmtParts < ActiveRecord::Migration 2 | def change 3 | create_table :hmt_parts do |t| 4 | 5 | t.timestamps null: false 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/dummy/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended that you check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(version: 20161210150343) do 15 | 16 | create_table "address_books", force: :cascade do |t| 17 | t.datetime "created_at", null: false 18 | t.datetime "updated_at", null: false 19 | end 20 | 21 | create_table "addresses", force: :cascade do |t| 22 | t.integer "addressable_id" 23 | t.string "addressable_type", limit: 255 24 | t.string "content", limit: 255 25 | t.datetime "created_at" 26 | t.datetime "updated_at" 27 | end 28 | 29 | add_index "addresses", ["addressable_id", "addressable_type"], name: "index_addresses_on_addressable_id_and_addressable_type" 30 | 31 | create_table "alphas", force: :cascade do |t| 32 | t.string "content", limit: 255 33 | t.integer "delta_id" 34 | t.datetime "created_at" 35 | t.datetime "updated_at" 36 | end 37 | 38 | add_index "alphas", ["delta_id"], name: "index_alphas_on_delta_id" 39 | 40 | create_table "assemblies", force: :cascade do |t| 41 | t.datetime "created_at", null: false 42 | t.datetime "updated_at", null: false 43 | end 44 | 45 | create_table "assemblies_parts", id: false, force: :cascade do |t| 46 | t.integer "assembly_id", null: false 47 | t.integer "part_id", null: false 48 | end 49 | 50 | add_index "assemblies_parts", ["assembly_id", "part_id"], name: "index_assemblies_parts_on_assembly_id_and_part_id" 51 | add_index "assemblies_parts", ["part_id", "assembly_id"], name: "index_assemblies_parts_on_part_id_and_assembly_id" 52 | 53 | create_table "beta", force: :cascade do |t| 54 | t.string "content", limit: 255 55 | t.integer "alpha_id" 56 | t.datetime "created_at" 57 | t.datetime "updated_at" 58 | end 59 | 60 | add_index "beta", ["alpha_id"], name: "index_beta_on_alpha_id" 61 | 62 | create_table "big_companies", force: :cascade do |t| 63 | t.datetime "created_at", null: false 64 | t.datetime "updated_at", null: false 65 | end 66 | 67 | create_table "capas", force: :cascade do |t| 68 | t.string "content", limit: 255 69 | t.integer "beta_id" 70 | t.datetime "created_at" 71 | t.datetime "updated_at" 72 | end 73 | 74 | add_index "capas", ["beta_id"], name: "index_capas_on_beta_id" 75 | 76 | create_table "cars", force: :cascade do |t| 77 | t.integer "user_id" 78 | t.string "content", limit: 255 79 | t.datetime "created_at" 80 | t.datetime "updated_at" 81 | end 82 | 83 | add_index "cars", ["user_id"], name: "index_cars_on_user_id" 84 | 85 | create_table "coffees", force: :cascade do |t| 86 | t.integer "coffeeable_id" 87 | t.string "coffeeable_type" 88 | t.datetime "created_at", null: false 89 | t.datetime "updated_at", null: false 90 | end 91 | 92 | add_index "coffees", ["coffeeable_type", "coffeeable_id"], name: "index_coffees_on_coffeeable_type_and_coffeeable_id" 93 | 94 | create_table "contacts", force: :cascade do |t| 95 | t.integer "user_id" 96 | t.string "content", limit: 255 97 | t.datetime "created_at" 98 | t.datetime "updated_at" 99 | t.integer "contactable_id" 100 | t.string "contactable_type" 101 | end 102 | 103 | add_index "contacts", ["contactable_type", "contactable_id"], name: "index_contacts_on_contactable_type_and_contactable_id" 104 | add_index "contacts", ["user_id"], name: "index_contacts_on_user_id" 105 | 106 | create_table "delta", force: :cascade do |t| 107 | t.string "content", limit: 255 108 | t.integer "capa_id" 109 | t.datetime "created_at" 110 | t.datetime "updated_at" 111 | end 112 | 113 | add_index "delta", ["capa_id"], name: "index_delta_on_capa_id" 114 | 115 | create_table "events", force: :cascade do |t| 116 | t.integer "work_order_id" 117 | t.datetime "created_at", null: false 118 | t.datetime "updated_at", null: false 119 | end 120 | 121 | add_index "events", ["work_order_id"], name: "index_events_on_work_order_id" 122 | 123 | create_table "geo_locations", force: :cascade do |t| 124 | t.integer "address_id" 125 | t.string "content", limit: 255 126 | t.datetime "created_at" 127 | t.datetime "updated_at" 128 | end 129 | 130 | add_index "geo_locations", ["address_id"], name: "index_geo_locations_on_address_id" 131 | 132 | create_table "hmt_assemblies", force: :cascade do |t| 133 | t.datetime "created_at", null: false 134 | t.datetime "updated_at", null: false 135 | end 136 | 137 | create_table "hmt_parts", force: :cascade do |t| 138 | t.datetime "created_at", null: false 139 | t.datetime "updated_at", null: false 140 | end 141 | 142 | create_table "parts", force: :cascade do |t| 143 | t.datetime "created_at", null: false 144 | t.datetime "updated_at", null: false 145 | end 146 | 147 | create_table "phones", force: :cascade do |t| 148 | t.integer "phoneable_id" 149 | t.string "phoneable_type", limit: 255 150 | t.string "content", limit: 255 151 | t.datetime "created_at", null: false 152 | t.datetime "updated_at", null: false 153 | end 154 | 155 | add_index "phones", ["phoneable_id", "phoneable_type"], name: "index_phones_on_phoneable_id_and_phoneable_type" 156 | 157 | create_table "photos", force: :cascade do |t| 158 | t.integer "photoable_id" 159 | t.string "photoable_type", limit: 255 160 | t.string "content", limit: 255 161 | t.datetime "created_at" 162 | t.datetime "updated_at" 163 | end 164 | 165 | add_index "photos", ["photoable_id", "photoable_type"], name: "index_photos_on_photoable_id_and_photoable_type" 166 | 167 | create_table "profiles", force: :cascade do |t| 168 | t.integer "profileable_id" 169 | t.string "profileable_type", limit: 255 170 | t.string "content", limit: 255 171 | t.datetime "created_at" 172 | t.datetime "updated_at" 173 | end 174 | 175 | add_index "profiles", ["profileable_id", "profileable_type"], name: "index_profiles_on_profileable_id_and_profileable_type" 176 | 177 | create_table "squishies", force: :cascade do |t| 178 | t.string "content", limit: 255 179 | t.integer "squishable_id" 180 | t.string "squishable_type", limit: 255 181 | t.datetime "created_at" 182 | t.datetime "updated_at" 183 | end 184 | 185 | add_index "squishies", ["squishable_id", "squishable_type"], name: "index_squishies_on_squishable_id_and_squishable_type" 186 | 187 | create_table "ssns", force: :cascade do |t| 188 | t.integer "user_id" 189 | t.string "content", limit: 255 190 | t.datetime "created_at" 191 | t.datetime "updated_at" 192 | end 193 | 194 | add_index "ssns", ["user_id"], name: "index_ssns_on_user_id" 195 | 196 | create_table "tags", force: :cascade do |t| 197 | t.integer "user_id" 198 | t.string "content", limit: 255 199 | t.datetime "created_at", null: false 200 | t.datetime "updated_at", null: false 201 | end 202 | 203 | add_index "tags", ["user_id"], name: "index_tags_on_user_id" 204 | 205 | create_table "tires", force: :cascade do |t| 206 | t.integer "user_id" 207 | t.integer "car_id" 208 | t.string "content", limit: 255 209 | t.datetime "created_at" 210 | t.datetime "updated_at" 211 | end 212 | 213 | add_index "tires", ["car_id"], name: "index_tires_on_car_id" 214 | add_index "tires", ["user_id"], name: "index_tires_on_user_id" 215 | 216 | create_table "users", force: :cascade do |t| 217 | t.string "content", limit: 255 218 | t.datetime "created_at", null: false 219 | t.datetime "updated_at", null: false 220 | end 221 | 222 | create_table "work_orders", force: :cascade do |t| 223 | t.datetime "created_at", null: false 224 | t.datetime "updated_at", null: false 225 | t.integer "big_company_id" 226 | end 227 | 228 | add_index "work_orders", ["big_company_id"], name: "index_work_orders_on_big_company_id" 229 | 230 | end 231 | -------------------------------------------------------------------------------- /test/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielpclark/PolyBelongsTo/38d51d37f9148613519d6b6d56bdf4d0884f0e86/test/dummy/lib/assets/.keep -------------------------------------------------------------------------------- /test/dummy/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielpclark/PolyBelongsTo/38d51d37f9148613519d6b6d56bdf4d0884f0e86/test/dummy/log/.keep -------------------------------------------------------------------------------- /test/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielpclark/PolyBelongsTo/38d51d37f9148613519d6b6d56bdf4d0884f0e86/test/dummy/public/favicon.ico -------------------------------------------------------------------------------- /test/dummy/test/fixtures/assemblies.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | # This model initially had no columns defined. If you add columns to the 5 | # model remove the '{}' from the fixture names and add the columns immediately 6 | # below each fixture, per the syntax in the comments below 7 | # 8 | one: {} 9 | # column: value 10 | # 11 | two: {} 12 | # column: value 13 | -------------------------------------------------------------------------------- /test/dummy/test/fixtures/big_companies.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | # This model initially had no columns defined. If you add columns to the 5 | # model remove the '{}' from the fixture names and add the columns immediately 6 | # below each fixture, per the syntax in the comments below 7 | # 8 | one: {} 9 | # column: value 10 | # 11 | two: {} 12 | # column: value 13 | -------------------------------------------------------------------------------- /test/dummy/test/fixtures/coffees.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | one: 5 | coffeeable: 6 | 7 | two: 8 | coffeeable: 9 | -------------------------------------------------------------------------------- /test/dummy/test/fixtures/events.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | one: 5 | work_order_id: 1 6 | 7 | two: 8 | work_order_id: 1 9 | -------------------------------------------------------------------------------- /test/dummy/test/fixtures/hmt_assemblies.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | # This model initially had no columns defined. If you add columns to the 5 | # model remove the '{}' from the fixture names and add the columns immediately 6 | # below each fixture, per the syntax in the comments below 7 | # 8 | one: {} 9 | # column: value 10 | # 11 | two: {} 12 | # column: value 13 | -------------------------------------------------------------------------------- /test/dummy/test/fixtures/hmt_parts.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | # This model initially had no columns defined. If you add columns to the 5 | # model remove the '{}' from the fixture names and add the columns immediately 6 | # below each fixture, per the syntax in the comments below 7 | # 8 | one: {} 9 | # column: value 10 | # 11 | two: {} 12 | # column: value 13 | -------------------------------------------------------------------------------- /test/dummy/test/fixtures/parts.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | # This model initially had no columns defined. If you add columns to the 5 | # model remove the '{}' from the fixture names and add the columns immediately 6 | # below each fixture, per the syntax in the comments below 7 | # 8 | one: {} 9 | # column: value 10 | # 11 | two: {} 12 | # column: value 13 | -------------------------------------------------------------------------------- /test/dummy/test/fixtures/work_orders.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | # This model initially had no columns defined. If you add columns to the 5 | # model remove the '{}' from the fixture names and add the columns immediately 6 | # below each fixture, per the syntax in the comments below 7 | # 8 | one: {} 9 | # column: value 10 | # 11 | two: {} 12 | # column: value 13 | -------------------------------------------------------------------------------- /test/dummy/test/models/address_book_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class AddressBookTest < ActiveSupport::TestCase 4 | 5 | def address_book 6 | @address_book ||= AddressBook.new 7 | end 8 | 9 | def test_valid 10 | assert address_book.valid? 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /test/dummy/test/models/assembly_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class AssemblyTest < ActiveSupport::TestCase 4 | 5 | def assembly 6 | @assembly ||= Assembly.new 7 | end 8 | 9 | def test_valid 10 | assert assembly.valid? 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /test/dummy/test/models/big_company_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class BigCompanyTest < ActiveSupport::TestCase 4 | 5 | def big_company 6 | @big_company ||= BigCompany.new 7 | end 8 | 9 | def test_valid 10 | assert big_company.valid? 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /test/dummy/test/models/coffee_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class CoffeeTest < ActiveSupport::TestCase 4 | 5 | def coffee 6 | @coffee ||= Coffee.new 7 | end 8 | 9 | def test_valid 10 | assert coffee.valid? 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /test/dummy/test/models/event_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class EventTest < ActiveSupport::TestCase 4 | 5 | def event 6 | @event ||= Event.new 7 | end 8 | 9 | def test_valid 10 | assert event.valid? 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /test/dummy/test/models/hmt_assembly_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class HmtAssemblyTest < ActiveSupport::TestCase 4 | 5 | def hmt_assembly 6 | @hmt_assembly ||= HmtAssembly.new 7 | end 8 | 9 | def test_valid 10 | assert hmt_assembly.valid? 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /test/dummy/test/models/hmt_part_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class HmtPartTest < ActiveSupport::TestCase 4 | 5 | def hmt_part 6 | @hmt_part ||= HmtPart.new 7 | end 8 | 9 | def test_valid 10 | assert hmt_part.valid? 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /test/dummy/test/models/part_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class PartTest < ActiveSupport::TestCase 4 | 5 | def part 6 | @part ||= Part.new 7 | end 8 | 9 | def test_valid 10 | assert part.valid? 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /test/dummy/test/models/work_order_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class WorkOrderTest < ActiveSupport::TestCase 4 | 5 | def work_order 6 | @work_order ||= WorkOrder.new 7 | end 8 | 9 | def test_valid 10 | assert work_order.valid? 11 | end 12 | 13 | end 14 | -------------------------------------------------------------------------------- /test/dup_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | require 'minitest/autorun' 3 | 4 | class DupTest < ActiveSupport::TestCase 5 | fixtures :all 6 | 7 | describe PolyBelongsTo::Dup do 8 | it "has method :pbt_dup_build" do 9 | User.instance_methods.must_include(:pbt_dup_build) 10 | User.methods.must_include(:pbt_dup_build) 11 | end 12 | 13 | it "has method :pbt_deep_dup_build" do 14 | User.instance_methods.must_include(:pbt_deep_dup_build) 15 | User.methods.must_include(:pbt_deep_dup_build) 16 | end 17 | 18 | it "#pbt_dup_build builds copy from dup'd attributes" do 19 | user = users(:bob) 20 | susan_prof = profiles(:susan_prof) 21 | contact = user.contacts.new 22 | contact.pbt_dup_build( susan_prof ) 23 | CleanAttrs[contact.profile].must_equal CleanAttrs[susan_prof] 24 | end 25 | 26 | it "#pbt_deep_dup_build builds deep copy of dup'd attributes" do 27 | user1 = users(:steve) 28 | bob_prof = profiles(:bob_prof) 29 | contact = user1.contacts.new 30 | contact.pbt_deep_dup_build(bob_prof) 31 | CleanAttrs[contact.profile ]. 32 | must_equal CleanAttrs[bob_prof] 33 | CleanAttrs[contact.profile.addresses.first ]. 34 | must_equal CleanAttrs[bob_prof.addresses.first] 35 | CleanAttrs[contact.profile.addresses.first.squishies.first ]. 36 | must_equal CleanAttrs[bob_prof.addresses.first.squishies.first] 37 | CleanAttrs[contact.profile.addresses.first.geo_location ]. 38 | must_equal CleanAttrs[bob_prof.addresses.first.geo_location] 39 | CleanAttrs[contact.profile.addresses.first.geo_location.squishies.first ]. 40 | must_equal CleanAttrs[bob_prof.addresses.first.geo_location.squishies.first] 41 | CleanAttrs[contact.profile.addresses.last ]. 42 | must_equal CleanAttrs[bob_prof.addresses.last] 43 | CleanAttrs[contact.profile.phones.first ]. 44 | must_equal CleanAttrs[bob_prof.phones.first] 45 | CleanAttrs[contact.profile.phones.first.squishy ]. 46 | must_equal CleanAttrs[bob_prof.phones.first.squishy] 47 | CleanAttrs[contact.profile.phones.last ]. 48 | must_equal CleanAttrs[bob_prof.phones.last] 49 | CleanAttrs[contact.profile.photo ]. 50 | must_equal CleanAttrs[bob_prof.photo] 51 | end 52 | end 53 | 54 | describe "PolyBelongsTo::Dup #pbt_deep_dup_build handles circular references like a champ!" do 55 | alpha = Alpha.new; alpha.save 56 | beta = alpha.betas.build; beta.save 57 | capa = beta.capas.build; capa.save 58 | delta = capa.deltas.build; delta.save 59 | alpha.update(delta_id: delta.id) 60 | 61 | it "is a circle" do 62 | alpha.pbt_parent.must_equal delta 63 | beta.pbt_parent.must_equal alpha 64 | capa.pbt_parent.must_equal beta 65 | delta.pbt_parent.must_equal capa 66 | end 67 | 68 | it "clones without duplicating cirular reference" do 69 | alpha2 = Alpha.new( CleanAttrs[alpha] ) 70 | CleanAttrs[alpha2].must_equal CleanAttrs[alpha] 71 | alpha2.pbt_deep_dup_build(beta) 72 | CleanAttrs[alpha2.betas.first].must_equal CleanAttrs[beta] 73 | CleanAttrs[alpha2.betas.first.capas.first].must_equal CleanAttrs[capa] 74 | CleanAttrs[alpha2.betas.first.capas.first.deltas.first].must_equal CleanAttrs[delta] 75 | CleanAttrs[alpha2.betas.first.capas.first.deltas.first.alphas.first].must_equal CleanAttrs[alpha] 76 | alpha2.betas.first.capas.first.deltas.first.alphas.first.betas.first.must_be_nil 77 | end 78 | 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /test/faked_collection_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | require 'minitest/autorun' 3 | 4 | class FakedCollectionTest < ActiveSupport::TestCase 5 | fixtures :all 6 | 7 | let(:steve_photos) do 8 | steve_prof = users(:steve).profiles.first 9 | PolyBelongsTo::FakedCollection.new(steve_prof, Photo) 10 | end 11 | 12 | let(:null_object) do 13 | PolyBelongsTo::FakedCollection.new() 14 | end 15 | 16 | let(:nil_steve) do 17 | PolyBelongsTo::FakedCollection.new(users(:steve), nil) 18 | end 19 | 20 | let(:nil_photo) do 21 | PolyBelongsTo::FakedCollection.new(nil, Photo) 22 | end 23 | 24 | describe PolyBelongsTo::FakedCollection do 25 | 26 | it "#class.name is named correctly" do 27 | steve_photos.class.name.must_equal "PolyBelongsTo::FakedCollection" 28 | end 29 | 30 | it "#superclass knows its superclass" do 31 | PolyBelongsTo::FakedCollection.superclass.must_equal Object 32 | end 33 | 34 | it "IDs the inner ited on :id" do 35 | [nil, photos(:steve_photo).id].must_include steve_photos.id 36 | nil_steve.id.must_be_nil 37 | nil_photo.id.must_be_nil 38 | null_object.id.must_be_nil 39 | end 40 | 41 | it "#all is an Array" do 42 | steve_photos.all.is_a?( Array).must_be_same_as true 43 | steve_photos.all.must_be_kind_of( Array) 44 | steve_photos.all.must_be_instance_of(Array) 45 | null_object.all.must_equal [] 46 | nil_steve.all.must_equal [] 47 | nil_photo.all.must_equal [] 48 | end 49 | 50 | it "checks if #empty?" do 51 | steve_photos.wont_be :empty? 52 | null_object.must_be :empty? 53 | nil_steve.must_be :empty? 54 | nil_photo.must_be :empty? 55 | end 56 | 57 | it "checks validity with #valid?" do 58 | steve_photos.must_be :valid? 59 | null_object.wont_be :valid? 60 | nil_steve.wont_be :valid? 61 | nil_photo.wont_be :valid? 62 | end 63 | 64 | it "gives true or false on #present?" do 65 | steve_photos.must_be :present? 66 | null_object.wont_be :present? 67 | nil_steve.wont_be :present? 68 | nil_photo.wont_be :present? 69 | end 70 | 71 | it "works with #presence" do 72 | steve_photos.presence.must_equal steve_photos 73 | null_object.presence.must_be_nil 74 | nil_steve.presence.must_be_nil 75 | nil_photo.presence.must_be_nil 76 | end 77 | 78 | it "#first is the item" do 79 | steve_photos.first.class.name.must_equal "Photo" 80 | null_object.first.must_be_nil 81 | nil_steve.first.must_be_nil 82 | nil_photo.first.must_be_nil 83 | end 84 | 85 | it "#last is the item" do 86 | steve_photos.last.class.name.must_equal "Photo" 87 | null_object.last.must_be_nil 88 | nil_steve.last.must_be_nil 89 | nil_photo.last.must_be_nil 90 | end 91 | 92 | it "#count and #size counts as 1 or 0" do 93 | steve_photos.count.between?(0, 1).must_be_same_as true 94 | [0, 1].must_include steve_photos.count 95 | null_object.count.must_be_same_as 0 96 | nil_steve.count.must_be_same_as 0 97 | nil_photo.count.must_be_same_as 0 98 | steve_photos.size.between?(0, 1).must_be_same_as true 99 | [0, 1].must_include steve_photos.size 100 | null_object.size.must_be_same_as 0 101 | nil_steve.size.must_be_same_as 0 102 | nil_photo.size.must_be_same_as 0 103 | end 104 | 105 | it "#ancestors has ActiveRecord::Base ancestor" do 106 | steve_photos.ancestors.must_include(ActiveRecord::Base) 107 | end 108 | 109 | it "#ancestors has NilClass if empty" do 110 | null_object.ancestors.must_include(NilClass) 111 | nil_steve.ancestors.must_include(NilClass) 112 | nil_photo.ancestors.must_include(NilClass) 113 | end 114 | 115 | it "build #kind_of? FakedCollection object" do 116 | steve_photos.must_be_kind_of(PolyBelongsTo::FakedCollection) 117 | null_object.must_be_kind_of(PolyBelongsTo::FakedCollection) 118 | end 119 | 120 | it "build #is_a? FakedCollection object" do 121 | steve_photos.is_a?(PolyBelongsTo::FakedCollection).must_be_same_as true 122 | null_object.is_a?(PolyBelongsTo::FakedCollection).must_be_same_as true 123 | end 124 | 125 | it "build #instance_of? FakedCollection object" do 126 | steve_photos.must_be_instance_of(PolyBelongsTo::FakedCollection) 127 | null_object.must_be_instance_of(PolyBelongsTo::FakedCollection) 128 | end 129 | 130 | it "#build builds appropriately" do 131 | steve_photos.build({content: "cheese"}) 132 | steve_photos.first.content.must_equal "cheese" 133 | ->{ null_object.build({content: "cheese"}) }.must_raise TypeError 134 | ->{ nil_steve.build( {content: "cheese"}) }.must_raise TypeError 135 | ->{ nil_photo.build( {content: "cheese"}) }.must_raise TypeError 136 | end 137 | 138 | it "#build returns self and not nil" do 139 | res = steve_photos.build({content: "cheese"}) 140 | res.wont_be_nil 141 | res.class.name.must_equal steve_photos.class.name 142 | res.first.content.must_equal "cheese" 143 | steve_photos.first.content.must_equal "cheese" 144 | end 145 | 146 | it "#each loops appropriately" do 147 | steve_photos.each do |photo| 148 | photo.class.name.must_equal "Photo" 149 | end 150 | end 151 | 152 | it "defines #klass to point to inner items class" do 153 | steve_photos.klass.name.must_equal "Photo" 154 | end 155 | 156 | it "#respond_to? :first and :last" do 157 | steve_photos.must_respond_to(:first) 158 | steve_photos.must_respond_to(:last) 159 | end 160 | 161 | it "knows sneeze is a missing method" do 162 | ->{steve_photos.sneeze}.must_raise NoMethodError 163 | end 164 | 165 | it "has method_missing forward appropriate calls" do 166 | steve_photos.method_missing(:nil?).must_equal false 167 | null_object.method_missing(:nil?).must_equal true 168 | end 169 | 170 | it "will not initialize on has_many" do 171 | steve = users(:steve) 172 | ->{ PolyBelongsTo::FakedCollection.new(steve, Profile) }.must_raise RuntimeError 173 | end 174 | 175 | it "takes nil Objects and returns an empty FakedCollection" do 176 | nil_photo.must_be :empty? 177 | nil_photo.all.must_equal [] 178 | nil_photo.size.must_be_same_as 0 179 | nil_photo.instance_eval {@instance}.must_be_nil 180 | nil_photo.wont_be :valid? 181 | 182 | nil_steve.all.must_equal [] 183 | nil_steve.size.must_be_same_as 0 184 | nil_steve.must_be :empty? 185 | nil_steve.instance_eval {@instance}.must_be_nil 186 | nil_steve.wont_be :valid? 187 | 188 | null_object.all.must_equal [] 189 | null_object.size.must_be_same_as 0 190 | null_object.must_be :empty? 191 | null_object.instance_eval {@instance}.must_be_nil 192 | null_object.wont_be :valid? 193 | end 194 | 195 | end 196 | 197 | end 198 | -------------------------------------------------------------------------------- /test/fixtures/address_books.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | # This model initially had no columns defined. If you add columns to the 5 | # model remove the '{}' from the fixture names and add the columns immediately 6 | # below each fixture, per the syntax in the comments below 7 | bob_address_book: {} 8 | steve_address_book: {} 9 | susan_address_book: {} 10 | -------------------------------------------------------------------------------- /test/fixtures/addresses.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | bob_address: 5 | addressable_id: <%= ActiveRecord::FixtureSet.identify(:bob_prof) %> 6 | addressable_type: Profile 7 | content: <%= SecureRandom.hex %> 8 | 9 | steve_address: 10 | addressable_id: <%= ActiveRecord::FixtureSet.identify(:steve_prof) %> 11 | addressable_type: Profile 12 | content: <%= SecureRandom.hex %> 13 | 14 | susan_address: 15 | addressable_id: <%= ActiveRecord::FixtureSet.identify(:susan_prof) %> 16 | addressable_type: Profile 17 | content: <%= SecureRandom.hex %> 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/cars.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | honda_civic: 5 | user: <%= ActiveRecord::FixtureSet.identify(:bob) %> 6 | content: MyString 7 | -------------------------------------------------------------------------------- /test/fixtures/contacts.yml: -------------------------------------------------------------------------------- 1 | bob_contact: 2 | user_id: <%= ActiveRecord::FixtureSet.identify(:bob) %> 3 | contactable_id: <%= ActiveRecord::FixtureSet.identify(:bob_address_book) %> 4 | contactable_type: AddressBook 5 | content: <%= SecureRandom.hex %> 6 | 7 | #steve_contact: 8 | # user_id: <%= ActiveRecord::FixtureSet.identify(:steve) %> 9 | # contactable_id: <%= ActiveRecord::FixtureSet.identify(:steve_address_book) %> 10 | # contactable_type: AddressBook 11 | # content: <%= SecureRandom.hex %> 12 | # 13 | #susan_contact: 14 | # user_id: <%= ActiveRecord::FixtureSet.identify(:susan) %> 15 | # contactable_id: <%= ActiveRecord::FixtureSet.identify(:susan_address_book) %> 16 | # contactable_type: AddressBook 17 | # content: <%= SecureRandom.hex %> 18 | # 19 | -------------------------------------------------------------------------------- /test/fixtures/geo_locations.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | bob_geo_loc: 5 | address_id: <%= ActiveRecord::FixtureSet.identify(:bob_address) %> 6 | content: <%= SecureRandom.hex %> 7 | 8 | steve_geo_loc: 9 | address_id: <%= ActiveRecord::FixtureSet.identify(:steve_address) %> 10 | content: <%= SecureRandom.hex %> 11 | 12 | susan_geo_loc: 13 | address_id: <%= ActiveRecord::FixtureSet.identify(:susan_address) %> 14 | content: <%= SecureRandom.hex %> 15 | -------------------------------------------------------------------------------- /test/fixtures/phones.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | bob_phone: 4 | phoneable_id: <%= ActiveRecord::FixtureSet.identify(:bob_prof) %> 5 | phoneable_type: Profile 6 | content: <%= SecureRandom.hex %> 7 | steve_phone: 8 | phoneable_id: <%= ActiveRecord::FixtureSet.identify(:steve_prof) %> 9 | phoneable_type: Profile 10 | content: <%= SecureRandom.hex %> 11 | susan_phone: 12 | phoneable_id: <%= ActiveRecord::FixtureSet.identify(:susan_prof) %> 13 | phoneable_type: Profile 14 | content: <%= SecureRandom.hex %> 15 | -------------------------------------------------------------------------------- /test/fixtures/photos.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | 5 | bob_photo: 6 | photoable_id: <%= ActiveRecord::FixtureSet.identify(:bob_prof) %> 7 | photoable_type: Profile 8 | content: <%= SecureRandom.hex %> 9 | steve_photo: 10 | photoable_id: <%= ActiveRecord::FixtureSet.identify(:steve_prof) %> 11 | photoable_type: Profile 12 | content: <%= SecureRandom.hex %> 13 | susan_photo: 14 | photoable_id: <%= ActiveRecord::FixtureSet.identify(:susan_prof) %> 15 | photoable_type: Profile 16 | content: <%= SecureRandom.hex %> 17 | -------------------------------------------------------------------------------- /test/fixtures/profiles.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | bob_prof: 5 | profileable_id: <%= ActiveRecord::FixtureSet.identify(:bob) %> 6 | profileable_type: "User" 7 | content: <%= SecureRandom.hex %> 8 | steve_prof: 9 | profileable_id: <%= ActiveRecord::FixtureSet.identify(:steve) %> 10 | profileable_type: "User" 11 | content: <%= SecureRandom.hex %> 12 | susan_prof: 13 | profileable_id: <%= ActiveRecord::FixtureSet.identify(:susan) %> 14 | profileable_type: "User" 15 | content: <%= SecureRandom.hex %> 16 | -------------------------------------------------------------------------------- /test/fixtures/squishies.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | bob_squishy_address: 5 | content: Squishy 6 | squishable: bob_address (Address) 7 | 8 | bob_squishy_geo_loc: 9 | content: Squishy 10 | squishable: bob_geo_loc (GeoLocation) 11 | 12 | steve_squishy_address: 13 | content: Squishy 14 | squishable: steve_address (Address) 15 | 16 | steve_squishy_geo_loc: 17 | content: Squishy 18 | squishable: steve_geo_loc (GeoLocation) 19 | 20 | susan_squishy_address: 21 | content: Squishy 22 | squishable: susan_address (Address) 23 | 24 | susan_squishy_geo_loc: 25 | content: Squishy 26 | squishable: susan_geo_loc (GeoLocation) 27 | -------------------------------------------------------------------------------- /test/fixtures/ssns.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | bob_ssn: 5 | user_id: <%= ActiveRecord::FixtureSet.identify(:bob) %> 6 | content: <%= SecureRandom.hex %> 7 | 8 | steve_ssn: 9 | user_id: <%= ActiveRecord::FixtureSet.identify(:steve) %> 10 | content: <%= SecureRandom.hex %> 11 | 12 | susan_ssn: 13 | user_id: <%= ActiveRecord::FixtureSet.identify(:susan) %> 14 | content: <%= SecureRandom.hex %> 15 | -------------------------------------------------------------------------------- /test/fixtures/tags.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | bob_tag: 4 | user_id: <%= ActiveRecord::FixtureSet.identify(:bob) %> 5 | content: <%= SecureRandom.hex %> 6 | steve_tag: 7 | user_id: <%= ActiveRecord::FixtureSet.identify(:steve) %> 8 | content: <%= SecureRandom.hex %> 9 | susan_tag: 10 | user_id: <%= ActiveRecord::FixtureSet.identify(:susan) %> 11 | content: <%= SecureRandom.hex %> 12 | -------------------------------------------------------------------------------- /test/fixtures/tires.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at 2 | # http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html 3 | 4 | low_profile1: 5 | user: <%= ActiveRecord::FixtureSet.identify(:bob) %> 6 | car: <%= ActiveRecord::FixtureSet.identify(:honda_civic) %> 7 | content: MyString 8 | 9 | low_profile2: 10 | user: <%= ActiveRecord::FixtureSet.identify(:bob) %> 11 | car: <%= ActiveRecord::FixtureSet.identify(:honda_civic) %> 12 | content: MyString 13 | 14 | low_profile3: 15 | user: <%= ActiveRecord::FixtureSet.identify(:bob) %> 16 | car: <%= ActiveRecord::FixtureSet.identify(:honda_civic) %> 17 | content: MyString 18 | 19 | low_profile4: 20 | user: <%= ActiveRecord::FixtureSet.identify(:bob) %> 21 | car: <%= ActiveRecord::FixtureSet.identify(:honda_civic) %> 22 | content: MyString 23 | -------------------------------------------------------------------------------- /test/fixtures/users.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | # This model initially had no columns defined. If you add columns to the 4 | # model remove the '{}' from the fixture names and add the columns immediately 5 | # below each fixture, per the syntax in the comments below 6 | # 7 | bob: {} 8 | steve: {} 9 | susan: {} 10 | 11 | -------------------------------------------------------------------------------- /test/major_version_changes_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | require 'minitest/autorun' 3 | 4 | class MajorVersionChangesTest < ActiveSupport::TestCase 5 | fixtures :all 6 | 7 | describe "Test breaking changes between major versions" do 8 | 9 | let(:contact) { contacts(:bob_contact) } 10 | 11 | if Gem::Dependency.new('', "< 1.0.0").match?('', PolyBelongsTo::VERSION) 12 | it "pre 1.0.0 first parent relation" do 13 | contact.pbt.must_be_same_as :user 14 | Contact.pbt.must_be_same_as :user 15 | 16 | contact.pbts.must_include :user 17 | contact.pbts.must_include :contactable 18 | contact.pbts.first.must_be_same_as :user 19 | Contact.pbts.must_include :user 20 | Contact.pbts.must_include :contactable 21 | Contact.pbts.first.must_be_same_as :user 22 | end 23 | 24 | it "pre 1.0.0 :poly? on dual ownership with non-polymorphic first" do 25 | contact.poly?.must_be_same_as false 26 | Contact.poly?.must_be_same_as false 27 | end 28 | 29 | it "pre 1.0.0 :pbt_type_sym on dual ownership with non-polymorphic first" do 30 | contact.pbt_id_sym.must_be_same_as :user_id 31 | Contact.pbt_id_sym.must_be_same_as :user_id 32 | end 33 | 34 | it "pre 1.0.0 :pbt_parent returns first parent" do 35 | contact.pbt_parent.id.must_be_same_as users(:bob).id 36 | end 37 | else 38 | it "post 1.0.0 first polymorphic parent relation" do 39 | contact.pbt.must_be_same_as :contactable 40 | Contact.pbt.must_be_same_as :contactable 41 | 42 | contact.pbts.must_include :user 43 | contact.pbts.must_include :contactable 44 | contact.pbts.first.must_be_same_as :contactable 45 | Contact.pbts.must_include :user 46 | Contact.pbts.must_include :contactable 47 | Contact.pbts.first.must_be_same_as :contactable 48 | end 49 | 50 | it "post 1.0.0 :poly? on dual ownership with non-polymorphic first" do 51 | contact.poly?.must_be_same_as true 52 | Contact.poly?.must_be_same_as true 53 | end 54 | 55 | it "pre 1.0.0 :pbt_type_sym on dual ownership with non-polymorphic first" do 56 | contact.pbt_id_sym.must_be_same_as :contactable_id 57 | Contact.pbt_id_sym.must_be_same_as :contactable_id 58 | end 59 | 60 | it "post 1.0.0 :pbt_parent gives polymorphic parent precedence" do 61 | contact.pbt_parent.id.wont_equal users(:bob).id 62 | end 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /test/pbt_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | require 'minitest/autorun' 3 | 4 | class PbtTest < ActiveSupport::TestCase 5 | fixtures :all 6 | 7 | describe PolyBelongsTo::Pbt do 8 | it "AttrSanitizer removes conflicting attributes" do 9 | user = users(:bob) 10 | PolyBelongsTo::Pbt::AttrSanitizer[user].must_equal Hash[id: nil, content: user.content].stringify_keys 11 | PolyBelongsTo::Pbt::AttrSanitizer[nil ].must_equal Hash[] 12 | end 13 | 14 | it "BuildCmd returns build command" do 15 | profile = profiles(:bob_prof) 16 | "#{PolyBelongsTo::Pbt::BuildCmd[profile, Phone]}".must_equal "phones.build" 17 | "#{PolyBelongsTo::Pbt::BuildCmd[profile, Photo]}".must_equal "build_photo" 18 | PolyBelongsTo::Pbt::BuildCmd[nil, Photo].must_be_nil 19 | PolyBelongsTo::Pbt::BuildCmd[profile, nil].must_be_nil 20 | end 21 | 22 | it "Reflects returns has_one and has_many relationships" do 23 | profile = profiles(:bob_prof) 24 | PolyBelongsTo::Pbt::Reflects[profile].sort.must_equal [:phones, :addresses, :photo].sort 25 | PolyBelongsTo::Pbt::Reflects[nil ].must_equal Array[] 26 | end 27 | 28 | it "ReflectsAsClasses one and many relations as classes" do 29 | profile = profiles(:bob_prof) 30 | PolyBelongsTo::Pbt::ReflectsAsClasses[profile].map(&:hash).sort.must_equal [Phone, Address, Photo].map(&:hash).sort 31 | PolyBelongsTo::Pbt::ReflectsAsClasses[nil ].must_equal Array[] 32 | end 33 | 34 | it "Reflects & ReflectsAsClasses accept boolean for HABTM" do 35 | obj = Part.new 36 | PolyBelongsTo::Pbt::Reflects[obj, :habtm].must_equal [:assemblies] 37 | PolyBelongsTo::Pbt::ReflectsAsClasses[obj, :habtm].must_equal [Assembly] 38 | end 39 | 40 | it "IsReflected gives boolean of child" do 41 | profile = profiles(:bob_prof) 42 | PolyBelongsTo::Pbt::IsReflected[profile, Phone].must_equal true 43 | PolyBelongsTo::Pbt::IsReflected[profile, Address].must_equal true 44 | PolyBelongsTo::Pbt::IsReflected[profile, Photo].must_equal true 45 | PolyBelongsTo::Pbt::IsReflected[profile, User].must_equal false 46 | PolyBelongsTo::Pbt::IsReflected[nil, User].must_equal false 47 | PolyBelongsTo::Pbt::IsReflected[profile, nil].must_equal false 48 | end 49 | 50 | it "SingularOrPlural responds for child relations" do 51 | profile = profiles(:susan_prof) 52 | PolyBelongsTo::Pbt::SingularOrPlural[profile, Phone].must_equal :plural 53 | PolyBelongsTo::Pbt::SingularOrPlural[Alpha.new, Beta].must_equal :plural 54 | PolyBelongsTo::Pbt::SingularOrPlural[profile, Photo].must_equal :singular 55 | PolyBelongsTo::Pbt::SingularOrPlural[profile, User].must_be_nil 56 | PolyBelongsTo::Pbt::SingularOrPlural[nil, User].must_be_nil 57 | PolyBelongsTo::Pbt::SingularOrPlural[profile, nil].must_be_nil 58 | end 59 | 60 | it "IsSingular tells child singleness" do 61 | profile = profiles(:steve_prof) 62 | PolyBelongsTo::Pbt::IsSingular[profile, Phone].must_be_same_as false 63 | PolyBelongsTo::Pbt::IsSingular[nil, Phone].must_be_same_as false 64 | PolyBelongsTo::Pbt::IsSingular[profile, nil].must_be_same_as false 65 | PolyBelongsTo::Pbt::IsSingular[Alpha.new, Beta].must_be_same_as false 66 | PolyBelongsTo::Pbt::IsSingular[profile, Photo].must_be_same_as true 67 | end 68 | 69 | it "IsPlural tells child pluralness" do 70 | profile = profiles(:bob_prof) 71 | PolyBelongsTo::Pbt::IsPlural[profile, Phone].must_be_same_as true 72 | PolyBelongsTo::Pbt::IsPlural[Alpha.new, Beta].must_be_same_as true 73 | PolyBelongsTo::Pbt::IsPlural[profile, Photo].must_be_same_as false 74 | PolyBelongsTo::Pbt::IsPlural[nil, Photo].must_be_same_as false 75 | PolyBelongsTo::Pbt::IsPlural[profile, nil].must_be_same_as false 76 | end 77 | 78 | it "CollectionProxy singular or plural proxy name" do 79 | profile = profiles(:steve_prof) 80 | PolyBelongsTo::Pbt::CollectionProxy[profile, Phone].must_equal :phones 81 | PolyBelongsTo::Pbt::CollectionProxy[profile, Photo].must_equal :photo 82 | PolyBelongsTo::Pbt::CollectionProxy[Alpha.new, Beta].must_equal :betas 83 | PolyBelongsTo::Pbt::CollectionProxy[profile, User].must_be_nil 84 | PolyBelongsTo::Pbt::CollectionProxy[nil, User].must_be_nil 85 | PolyBelongsTo::Pbt::CollectionProxy[profile, nil].must_be_nil 86 | end 87 | 88 | it "AsCollectionProxy has_one emulated collectionproxy" do 89 | address = profiles(:bob_prof).addresses.first 90 | address_to_geo = PolyBelongsTo::Pbt::AsCollectionProxy[address, GeoLocation] 91 | address_to_geo.must_respond_to(:klass) 92 | address_to_geo.must_respond_to(:build) 93 | address_to_geo.must_respond_to(:each ) 94 | address_to_geo.must_respond_to(:all ) 95 | address_to_geo.must_respond_to(:first) 96 | address_to_geo.must_respond_to(:last ) 97 | address_to_geo.must_be_kind_of(PolyBelongsTo::FakedCollection) 98 | end 99 | 100 | it "AsCollectionProxy has one or zero items" do 101 | address = profiles(:bob_prof).addresses.first 102 | address_to_geo = PolyBelongsTo::Pbt::AsCollectionProxy[address, GeoLocation] 103 | address_to_geo.count.between?(0, 1).must_be_same_as true 104 | [0, 1].must_include address_to_geo.count 105 | address_to_geo.size.between?(0, 1).must_be_same_as true 106 | [0, 1].must_include address_to_geo.size 107 | end 108 | 109 | it "AsCollectionProxy has_many uses ActiveRecord::Associations::CollectionProxy" do 110 | bob = users(:bob) 111 | bob_to_prof = PolyBelongsTo::Pbt::AsCollectionProxy[bob, Profile] 112 | bob_to_prof.must_respond_to(:klass) 113 | bob_to_prof.must_respond_to(:build) 114 | bob_to_prof.must_respond_to(:each ) 115 | bob_to_prof.must_respond_to(:all ) 116 | bob_to_prof.must_respond_to(:first) 117 | bob_to_prof.must_respond_to(:last ) 118 | bob_to_prof.must_be_kind_of(ActiveRecord::Associations::CollectionProxy) 119 | end 120 | 121 | it "AsCollectionProxy returns empty FakedCollection when handed unrelated instances" do 122 | fc = PolyBelongsTo::Pbt::AsCollectionProxy[Alpha.new, Capa] 123 | fc.must_be_kind_of(PolyBelongsTo::FakedCollection) 124 | fc.must_be :empty? 125 | end 126 | 127 | it "sanity checks Reflects & ReflectsAsClasses possible snake_case CamelCase future changes" do 128 | [ 129 | [WorkOrder.new, :events, Event], 130 | [BigCompany.new, :work_orders, WorkOrder] 131 | ].each do |obj, a, b| 132 | PolyBelongsTo::Pbt::Reflects[obj].must_equal [a] 133 | PolyBelongsTo::Pbt::ReflectsAsClasses[obj].map(&:hash).must_equal [b].map(&:hash) 134 | end 135 | end 136 | end 137 | end 138 | -------------------------------------------------------------------------------- /test/singleton_set_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | require 'minitest/autorun' 3 | 4 | class DupTest < ActiveSupport::TestCase 5 | fixtures :all 6 | 7 | describe PolyBelongsTo::SingletonSet do 8 | let(:example){ users(:bob) } 9 | let(:the_set){ PolyBelongsTo::SingletonSet.new } 10 | 11 | it "formats name with #formatted_name" do 12 | the_set.formatted_name(example).must_equal "#{example.class.name}-#{example.id}" 13 | end 14 | 15 | it "adds with :add?" do 16 | the_set.add?(example) 17 | the_set.to_a.must_equal ["#{example.class.name}-#{example.id}"] 18 | end 19 | 20 | it "changes ActiveRecord Objects for method_missing with #formatted_name" do 21 | the_set.method_missing(:add, example) 22 | the_set.to_a.must_equal ["#{example.class.name}-#{example.id}"] 23 | end 24 | 25 | it "can tell you what's included" do 26 | the_set.<<(example) 27 | the_set.include?(example).must_be_same_as true 28 | end 29 | 30 | it "flags a duplicate" do 31 | the_set.<<(example) 32 | the_set.flagged?(example).must_be_same_as true 33 | the_set.instance_eval {@flagged}.to_a.must_equal ["#{example.class.name}-#{example.id}"] 34 | end 35 | 36 | it "says false for unflagged items" do 37 | the_set.flagged?(example).must_be_same_as false 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] = "test" 2 | # require "codeclimate-test-reporter" 3 | # CodeClimate::TestReporter.start 4 | require 'simplecov' 5 | SimpleCov.start 6 | require File.expand_path("../../test/dummy/config/environment.rb", __FILE__) 7 | 8 | ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../test/dummy/db/migrate", __FILE__)] 9 | require 'rails/test_help' 10 | require 'minitest/rails' 11 | require 'minitest/reporters' 12 | require 'color_pound_spec_reporter' 13 | require 'securerandom' 14 | 15 | unless Rails.version =~ /^4.[2-9]/ 16 | Rails.backtrace_cleaner.remove_silencers! 17 | end 18 | Minitest.backtrace_filter = Minitest::BacktraceFilter.new 19 | 20 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } 21 | 22 | if ActiveSupport::TestCase.respond_to?(:fixture_path=) 23 | ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__) 24 | end 25 | 26 | Minitest::Reporters.use! [ColorPoundSpecReporter.new] 27 | 28 | class ActiveSupport::TestCase 29 | CleanAttrs = PolyBelongsTo::Pbt::AttrSanitizer 30 | end 31 | --------------------------------------------------------------------------------