inventory_refresh 0.3.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +25 -30
  3. data/.github/workflows/ci.yaml +47 -0
  4. data/.rubocop.yml +3 -3
  5. data/.rubocop_cc.yml +3 -4
  6. data/.rubocop_local.yml +5 -2
  7. data/.whitesource +3 -0
  8. data/CHANGELOG.md +19 -0
  9. data/Gemfile +10 -4
  10. data/README.md +1 -2
  11. data/Rakefile +2 -2
  12. data/inventory_refresh.gemspec +9 -10
  13. data/lib/inventory_refresh/application_record_iterator.rb +25 -12
  14. data/lib/inventory_refresh/graph/topological_sort.rb +24 -26
  15. data/lib/inventory_refresh/graph.rb +2 -2
  16. data/lib/inventory_refresh/inventory_collection/builder.rb +37 -15
  17. data/lib/inventory_refresh/inventory_collection/data_storage.rb +9 -0
  18. data/lib/inventory_refresh/inventory_collection/helpers/initialize_helper.rb +147 -38
  19. data/lib/inventory_refresh/inventory_collection/helpers/questions_helper.rb +49 -5
  20. data/lib/inventory_refresh/inventory_collection/index/proxy.rb +35 -3
  21. data/lib/inventory_refresh/inventory_collection/index/type/base.rb +8 -0
  22. data/lib/inventory_refresh/inventory_collection/index/type/local_db.rb +2 -0
  23. data/lib/inventory_refresh/inventory_collection/index/type/skeletal.rb +1 -0
  24. data/lib/inventory_refresh/inventory_collection/reference.rb +1 -0
  25. data/lib/inventory_refresh/inventory_collection/references_storage.rb +17 -0
  26. data/lib/inventory_refresh/inventory_collection/scanner.rb +91 -3
  27. data/lib/inventory_refresh/inventory_collection/serialization.rb +16 -10
  28. data/lib/inventory_refresh/inventory_collection.rb +122 -64
  29. data/lib/inventory_refresh/inventory_object.rb +74 -40
  30. data/lib/inventory_refresh/inventory_object_lazy.rb +17 -10
  31. data/lib/inventory_refresh/null_logger.rb +2 -2
  32. data/lib/inventory_refresh/persister.rb +31 -65
  33. data/lib/inventory_refresh/save_collection/base.rb +4 -2
  34. data/lib/inventory_refresh/save_collection/saver/base.rb +114 -15
  35. data/lib/inventory_refresh/save_collection/saver/batch.rb +17 -0
  36. data/lib/inventory_refresh/save_collection/saver/concurrent_safe_batch.rb +129 -51
  37. data/lib/inventory_refresh/save_collection/saver/default.rb +57 -0
  38. data/lib/inventory_refresh/save_collection/saver/partial_upsert_helper.rb +2 -19
  39. data/lib/inventory_refresh/save_collection/saver/retention_helper.rb +68 -3
  40. data/lib/inventory_refresh/save_collection/saver/sql_helper.rb +125 -0
  41. data/lib/inventory_refresh/save_collection/saver/sql_helper_update.rb +10 -6
  42. data/lib/inventory_refresh/save_collection/saver/sql_helper_upsert.rb +28 -16
  43. data/lib/inventory_refresh/save_collection/sweeper.rb +17 -93
  44. data/lib/inventory_refresh/save_collection/topological_sort.rb +5 -5
  45. data/lib/inventory_refresh/save_inventory.rb +5 -12
  46. data/lib/inventory_refresh/target.rb +73 -0
  47. data/lib/inventory_refresh/target_collection.rb +92 -0
  48. data/lib/inventory_refresh/version.rb +1 -1
  49. data/lib/inventory_refresh.rb +2 -0
  50. metadata +42 -39
  51. data/.travis.yml +0 -23
  52. data/lib/inventory_refresh/exception.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 562e3672dadb805f4cd063f1ebd6151ee3defa02a4d72653d4d90984080d5825
4
- data.tar.gz: 303f14059268fa274404e1ca6757f76c65612dd5b75919029f712d812c27717d
3
+ metadata.gz: 8d788fa837920653d4f68b418a41687dcfb5555da780854c371654b93cf0fbaa
4
+ data.tar.gz: 516547253906ef09089351d6e007ebaac0160aaadee73a38782aa598f284e396
5
5
  SHA512:
6
- metadata.gz: 46c6e8b9bbeed08a8ca7860cac0e37a8d957335aa472f267445347f70bd3cf984b5d4eb3ef8f80ff1ed332bfd2b74c696568c3d8472d4bb0d5c4d9f3e65b51f5
7
- data.tar.gz: 1c5839b48a77df2edeb6307e79559c49b00d3971be5637d50d752d85249c2b730ecf01880151e57c3fd9788d22c9188b91f310fcd64c0cbe2565aa145420e09b
6
+ metadata.gz: c6b1fcf9600b6f9ff22da8cc5226f7c6395a7c35f9b9b62f9c0a2edb51158e1d3eaa59b1c1400b1e1ccf2f2bf1ff7bfa5901db04326afc490d569715daf73ad9
7
+ data.tar.gz: 50b1acc7a4b10a5a8a678b16fd06aa9c809068054d9b469391e877e668e18340ca998ab8485346d5f51cd0f682582fcd9ef516df2f88e273c1a401f45fe31241
data/.codeclimate.yml CHANGED
@@ -1,18 +1,21 @@
1
- ---
2
- exclude_paths:
3
- - ".git/"
4
- - "**.xml"
5
- - "**.yaml"
6
- - "**.yml"
7
- - "locale/"
8
- - "spec/"
9
- - "tools/"
10
- engines:
1
+ prepare:
2
+ fetch:
3
+ - url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/.rubocop_base.yml
4
+ path: ".rubocop_base.yml"
5
+ - url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/.rubocop_cc_base.yml
6
+ path: ".rubocop_cc_base.yml"
7
+ - url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/styles/base.yml
8
+ path: styles/base.yml
9
+ - url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/styles/cc_base.yml
10
+ path: styles/cc_base.yml
11
+ plugins:
12
+ rubocop:
13
+ enabled: true
14
+ config: ".rubocop_cc.yml"
15
+ channel: rubocop-0-82
11
16
  brakeman:
12
- # very slow :sad_panda:
13
17
  enabled: false
14
18
  bundler-audit:
15
- # requires Gemfile.lock
16
19
  enabled: false
17
20
  csslint:
18
21
  enabled: false
@@ -24,25 +27,17 @@ engines:
24
27
  - javascript
25
28
  eslint:
26
29
  enabled: false
27
- channel: "eslint-3"
30
+ channel: eslint-3
28
31
  fixme:
29
- # let's enable later
30
32
  enabled: false
31
33
  markdownlint:
32
- # let's enable later
33
34
  enabled: false
34
- rubocop:
35
- enabled: true
36
- config: '.rubocop_cc.yml'
37
- channel: rubocop-0-69
38
- prepare:
39
- fetch:
40
- - url: "https://raw.githubusercontent.com/ManageIQ/guides/master/.rubocop_base.yml"
41
- path: ".rubocop_base.yml"
42
- - url: "https://raw.githubusercontent.com/ManageIQ/guides/master/.rubocop_cc_base.yml"
43
- path: ".rubocop_cc_base.yml"
44
- ratings:
45
- paths:
46
- - Gemfile.lock
47
- - "**.rake"
48
- - "**.rb"
35
+ exclude_patterns:
36
+ - ".git/"
37
+ - "**.xml"
38
+ - "**.yaml"
39
+ - "**.yml"
40
+ - locale/
41
+ - spec/
42
+ - tools/
43
+ version: '2'
@@ -0,0 +1,47 @@
1
+ name: CI
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ ci:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ matrix:
10
+ ruby-version:
11
+ - '2.5'
12
+ - '2.6'
13
+ - '2.7'
14
+ rails-version:
15
+ - '5.2'
16
+ - '6.0'
17
+ - '6.1'
18
+ services:
19
+ postgres:
20
+ image: manageiq/postgresql:10
21
+ env:
22
+ POSTGRESQL_USER: root
23
+ POSTGRESQL_PASSWORD: smartvm
24
+ POSTGRESQL_DATABASE: inventory_refresh_dummy_test
25
+ options: --health-cmd pg_isready --health-interval 2s --health-timeout 5s --health-retries 5
26
+ ports:
27
+ - 5432:5432
28
+ env:
29
+ TEST_RAILS_VERSION: ${{ matrix.rails-version }}
30
+ PGHOST: localhost
31
+ PGPASSWORD: smartvm
32
+ CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
33
+ steps:
34
+ - uses: actions/checkout@v2
35
+ - name: Set up Ruby
36
+ uses: ruby/setup-ruby@v1
37
+ with:
38
+ ruby-version: ${{ matrix.ruby-version }}
39
+ bundler-cache: true
40
+ - name: Prepare tests
41
+ run: bundle exec rake spec:setup
42
+ - name: Run tests
43
+ run: bundle exec rake
44
+ - name: Report code coverage
45
+ if: ${{ github.ref == 'refs/heads/master' && matrix.ruby-version == '2.7' && matrix.rails-version == '6.1' }}
46
+ continue-on-error: true
47
+ uses: paambaati/codeclimate-action@v3.0.0
data/.rubocop.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  inherit_from:
2
- - https://raw.githubusercontent.com/ManageIQ/guides/master/.rubocop_base.yml
3
- # put all local rubocop config into .rubocop_local.yml as it will be loaded by .rubocop_cc.yml as well
4
- - .rubocop_local.yml
2
+ - ".rubocop_local.yml"
3
+ inherit_gem:
4
+ manageiq-style: ".rubocop_base.yml"
data/.rubocop_cc.yml CHANGED
@@ -1,5 +1,4 @@
1
1
  inherit_from:
2
- # this is downloaded by .codeclimate.yml
3
- - .rubocop_base.yml
4
- - .rubocop_cc_base.yml
5
- - .rubocop_local.yml
2
+ - ".rubocop_base.yml"
3
+ - ".rubocop_cc_base.yml"
4
+ - ".rubocop_local.yml"
data/.rubocop_local.yml CHANGED
@@ -1,2 +1,5 @@
1
- # GlobalVars:
2
- # AllowedVariables:
1
+ AllCops:
2
+ Exclude:
3
+ - spec/schema.rb
4
+ Rails:
5
+ Enabled: false
data/.whitesource ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "settingsInheritedFrom": "ManageIQ/whitesource-config@master"
3
+ }
data/CHANGELOG.md CHANGED
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ This project adheres to [Semantic Versioning](http://semver.org/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [1.0.0] - 2022-02-09
9
+ ### Changed
10
+ - Run rubocop -A (#102)
11
+ - Switch from travis to github actions (#104, #105)
12
+
13
+ ### Added
14
+ - **BREAKING** Add back support for non-concurrent-safe batch strategies (#101)
15
+ - Add support for Rails 6.1 (#103)
16
+ - Add bundler-inject (#106)
17
+
18
+ ### Fixed
19
+ - Fix InventoryCollection missing cache returns (#107)
data/Gemfile CHANGED
@@ -1,10 +1,16 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ plugin "bundler-inject", "~> 2.0"
4
+ require File.join(Bundler::Plugin.index.load_paths("bundler-inject")[0], "bundler-inject") rescue nil
4
5
 
5
6
  # Specify your gem's dependencies in inventory_refresh.gemspec
6
7
  gemspec
7
8
 
8
- # Load other additional Gemfiles
9
- # Developers can create a file ending in .rb under bundler.d/ to specify additional development dependencies
10
- Dir.glob(File.join(__dir__, 'bundler.d/*.rb')).each { |f| eval_gemfile(File.expand_path(f, __dir__)) }
9
+ case ENV['TEST_RAILS_VERSION']
10
+ when "5.2"
11
+ gem "activerecord", "~>5.2.6"
12
+ when "6.0"
13
+ gem "activerecord", "~>6.0.4"
14
+ when "6.1"
15
+ gem "activerecord", "~>6.1.4"
16
+ end
data/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # InventoryRefresh
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/inventory_refresh.svg)](http://badge.fury.io/rb/inventory_refresh)
4
- [![Build Status](https://travis-ci.org/ManageIQ/inventory_refresh.svg)](https://travis-ci.org/ManageIQ/inventory_refresh)
4
+ [![CI](https://github.com/ManageIQ/inventory_refresh/actions/workflows/ci.yaml/badge.svg)](https://github.com/ManageIQ/inventory_refresh/actions/workflows/ci.yaml)
5
5
  [![Code Climate](https://codeclimate.com/github/ManageIQ/inventory_refresh.svg)](https://codeclimate.com/github/ManageIQ/inventory_refresh)
6
6
  [![Test Coverage](https://codeclimate.com/github/ManageIQ/inventory_refresh/badges/coverage.svg)](https://codeclimate.com/github/ManageIQ/inventory_refresh/coverage)
7
- [![Security](https://hakiri.io/github/ManageIQ/inventory_refresh/master.svg)](https://hakiri.io/github/ManageIQ/inventory_refresh/master)
8
7
 
9
8
  [![Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ManageIQ/manageiq/providers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
10
9
 
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ namespace :spec do
12
12
 
13
13
  task :db_load_schema do
14
14
  require "active_record"
15
- with_connection(test_database_name) { load File.join(__dir__, %w{spec schema.rb}) }
15
+ with_connection(test_database_name) { load File.join(__dir__, %w[spec schema.rb]) }
16
16
  end
17
17
 
18
18
  desc "Setup test database"
@@ -20,7 +20,7 @@ namespace :spec do
20
20
 
21
21
  def connection_spec
22
22
  require 'yaml'
23
- @connection_spec ||= YAML.load_file(File.join(__dir__, %w(config database.yml)))
23
+ @connection_spec ||= YAML.load_file(File.join(__dir__, %w[config database.yml]))
24
24
  end
25
25
 
26
26
  def test_database_name
@@ -1,5 +1,4 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require "inventory_refresh/version"
5
4
 
@@ -8,30 +7,30 @@ Gem::Specification.new do |spec|
8
7
  spec.version = InventoryRefresh::VERSION
9
8
  spec.authors = ["ManageIQ Developers"]
10
9
 
11
- spec.summary = %q{Topological Inventory Persister}
12
- spec.description = %q{Topological Inventory Persister}
10
+ spec.summary = 'Topological Inventory Persister'
11
+ spec.description = 'Topological Inventory Persister'
13
12
  spec.homepage = "https://github.com/ManageIQ/inventory_refresh"
14
13
  spec.licenses = ["Apache-2.0"]
15
14
 
16
15
  # Specify which files should be added to the gem when it is released.
17
16
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
19
18
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
19
  end
21
20
  spec.bindir = "exe"
22
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
22
  spec.require_paths = ["lib"]
23
+ spec.metadata['rubygems_mfa_required'] = 'true'
24
24
 
25
- spec.add_dependency "activerecord", "~> 5.0"
26
- spec.add_dependency "more_core_extensions", "~> 3.5"
25
+ spec.add_dependency "activerecord", ">=5.0", "< 7.0"
26
+ spec.add_dependency "more_core_extensions", ">=3.5", "< 5"
27
27
  spec.add_dependency "pg", "> 0"
28
28
 
29
29
  spec.add_development_dependency "ancestry"
30
30
  spec.add_development_dependency "bundler", "~> 2.0"
31
31
  spec.add_development_dependency "factory_bot", "~> 4.11.1"
32
+ spec.add_development_dependency "manageiq-style"
32
33
  spec.add_development_dependency "rake", "~> 10.0"
33
34
  spec.add_development_dependency "rspec", "~> 3.0"
34
- spec.add_development_dependency "rubocop"
35
- spec.add_development_dependency "rubocop-performance"
36
- spec.add_development_dependency "simplecov"
35
+ spec.add_development_dependency "simplecov", ">= 0.21.2"
37
36
  end
@@ -1,12 +1,20 @@
1
1
  module InventoryRefresh
2
2
  class ApplicationRecordIterator
3
- attr_reader :inventory_collection
3
+ attr_reader :inventory_collection, :manager_uuids_set, :iterator, :query
4
4
 
5
- # An iterator that can fetch batches of the AR objects based on a set of attribute_indexes
5
+ # An iterator that can fetch batches of the AR objects based on a set of manager refs, or just mimics AR relation
6
+ # when given an iterator. Or given query, acts as iterator by selecting batches.
6
7
  #
7
8
  # @param inventory_collection [InventoryRefresh::InventoryCollection] Inventory collection owning the iterator
8
- def initialize(inventory_collection: nil)
9
+ # @param manager_uuids_set [Array<InventoryRefresh::InventoryCollection::Reference>] Array of references we want to
10
+ # fetch from the DB
11
+ # @param iterator [Proc] Block based iterator
12
+ # @query query [ActiveRecord::Relation] Existing query we want to use for querying the db
13
+ def initialize(inventory_collection: nil, manager_uuids_set: nil, iterator: nil, query: nil)
9
14
  @inventory_collection = inventory_collection
15
+ @manager_uuids_set = manager_uuids_set
16
+ @iterator = iterator
17
+ @query = query
10
18
  end
11
19
 
12
20
  # Iterator that mimics find_in_batches of ActiveRecord::Relation. This iterator serves for making more optimized query
@@ -17,22 +25,27 @@ module InventoryRefresh
17
25
  # and relation.where(:id => 500ids)
18
26
  #
19
27
  # @param batch_size [Integer] A batch size we want to fetch from DB
20
- # @param attributes_index [Hash{String => Hash}] Indexed hash with data we will be saving
21
28
  # @yield Code processing the batches
22
- def find_in_batches(batch_size: 1000, attributes_index: {})
23
- attributes_index.each_slice(batch_size) do |batch|
24
- yield(inventory_collection.db_collection_for_comparison_for(batch))
29
+ def find_in_batches(batch_size: 1000, &block)
30
+ if iterator
31
+ iterator.call(&block)
32
+ elsif query
33
+ manager_uuids_set.each_slice(batch_size) do |batch|
34
+ yield(query.where(inventory_collection.targeted_selection_for(batch)))
35
+ end
36
+ else
37
+ manager_uuids_set.each_slice(batch_size) do |batch|
38
+ yield(inventory_collection.db_collection_for_comparison_for(batch))
39
+ end
25
40
  end
26
41
  end
27
42
 
28
43
  # Iterator that mimics find_each of ActiveRecord::Relation using find_in_batches (see #find_in_batches)
29
44
  #
30
45
  # @yield Code processing the batches
31
- def find_each(attributes_index: {})
32
- find_in_batches(:attributes_index => attributes_index) do |batch|
33
- batch.each do |item|
34
- yield(item)
35
- end
46
+ def find_each(&block)
47
+ find_in_batches do |batch|
48
+ batch.each(&block)
36
49
  end
37
50
  end
38
51
  end
@@ -8,30 +8,30 @@ module InventoryRefresh
8
8
  @graph = graph
9
9
  end
10
10
 
11
- ################################################################################################################
12
- # Topological sort of the graph of the DTO collections to find the right order of saving DTO collections and
13
- # identify what DTO collections can be saved in parallel.
14
- # Does not mutate graph.
15
- #
16
- # @return [Array<Array>] Array of arrays(layers) of InventoryCollection objects
17
- ################################################################################################################
18
- # The expected input here is the directed acyclic Graph G (inventory_collections), consisting of Vertices(Nodes) V and
19
- # Edges E:
20
- # G = (V, E)
21
- #
22
- # The directed edge is defined as (u, v), where u is the dependency of v, i.e. arrow comes from u to v:
23
- # (u, v) ∈ E and u,v ∈ V
24
- #
25
- # S0 is a layer that has no dependencies:
26
- # S0 = { v ∈ V ∣ ∀u ∈ V.(u,v) ∉ E}
27
- #
28
- # Si+1 is a layer whose dependencies are in the sum of the previous layers from i to 0, cannot write
29
- # mathematical sum using U in text editor, so there is an alternative format using _(sum)
30
- # Si+1 = { v ∈ V ∣ ∀u ∈ V.(u,v) ∈ E → u ∈ _(sum(S0..Si))_ }
31
- #
32
- # Then each Si can have their Vertices(DTO collections) processed in parallel. This algorithm cannot
33
- # identify independent sub-graphs inside of the layers Si, so we can make the processing even more effective.
34
- ################################################################################################################
11
+ ################################################################################################################
12
+ # Topological sort of the graph of the DTO collections to find the right order of saving DTO collections and
13
+ # identify what DTO collections can be saved in parallel.
14
+ # Does not mutate graph.
15
+ #
16
+ # @return [Array<Array>] Array of arrays(layers) of InventoryCollection objects
17
+ ################################################################################################################
18
+ # The expected input here is the directed acyclic Graph G (inventory_collections), consisting of Vertices(Nodes) V and
19
+ # Edges E:
20
+ # G = (V, E)
21
+ #
22
+ # The directed edge is defined as (u, v), where u is the dependency of v, i.e. arrow comes from u to v:
23
+ # (u, v) ∈ E and u,v ∈ V
24
+ #
25
+ # S0 is a layer that has no dependencies:
26
+ # S0 = { v ∈ V ∣ ∀u ∈ V.(u,v) ∉ E}
27
+ #
28
+ # Si+1 is a layer whose dependencies are in the sum of the previous layers from i to 0, cannot write
29
+ # mathematical sum using U in text editor, so there is an alternative format using _(sum)
30
+ # Si+1 = { v ∈ V ∣ ∀u ∈ V.(u,v) ∈ E → u ∈ _(sum(S0..Si))_ }
31
+ #
32
+ # Then each Si can have their Vertices(DTO collections) processed in parallel. This algorithm cannot
33
+ # identify independent sub-graphs inside of the layers Si, so we can make the processing even more effective.
34
+ ################################################################################################################
35
35
  def topological_sort
36
36
  nodes = graph.nodes.dup
37
37
  edges = graph.edges
@@ -45,14 +45,12 @@ module InventoryRefresh
45
45
  max_depth -= 1
46
46
  if max_depth <= 0
47
47
  message = "Max depth reached while doing topological sort, your graph probably contains a cycle"
48
- #logger.error("#{message}:\n#{graph.to_graphviz}")
49
48
  raise "#{message} (see log)"
50
49
  end
51
50
 
52
51
  set, nodes = nodes.partition { |v| edges.select { |e| e.second == v }.all? { |e| sets.flatten.include?(e.first) } }
53
52
  if set.blank?
54
53
  message = "Blank dependency set while doing topological sort, your graph probably contains a cycle"
55
- #logger.error("#{message}:\n#{graph.to_graphviz}")
56
54
  raise "#{message} (see log)"
57
55
  end
58
56
 
@@ -37,7 +37,7 @@ module InventoryRefresh
37
37
  s << " #{node_names[from]} -> #{node_names[to]};"
38
38
  end
39
39
  s << "}"
40
- s.join("\n") + "\n"
40
+ "#{s.join("\n")}\n"
41
41
  end
42
42
 
43
43
  protected
@@ -147,7 +147,7 @@ module InventoryRefresh
147
147
  nodes.group_by { |n| n.respond_to?(:name) ? n.name.to_s : n.to_s }.each do |base_name, ns|
148
148
  ns.each_with_index do |n, i|
149
149
  name = ns.size == 1 ? base_name : "#{base_name}_#{i}"
150
- name = '"' + name.gsub(/["\\]/) { |c| "\\" + c } + '"' unless name =~ /^[A-Za-z0-9_]+$/
150
+ name = "\"#{name.gsub(/["\\]/) { |c| "\\#{c}" }}\"" unless /^[A-Za-z0-9_]+$/.match?(name)
151
151
  node_names[n] = name
152
152
  end
153
153
  end
@@ -4,17 +4,39 @@ module InventoryRefresh
4
4
  class MissingModelClassError < StandardError; end
5
5
 
6
6
  def self.allowed_properties
7
- %i(arel association
8
- attributes_blacklist attributes_whitelist batch_extra_attributes
9
- complete create_only custom_save_block
10
- custom_reconnect_block default_values
11
- dependency_attributes check_changed inventory_object_attributes
12
- manager_ref manager_ref_allowed_nil
13
- model_class name parent
14
- retention_strategy strategy
15
- secondary_refs
16
- update_only use_ar_object
17
- assert_graph_integrity).to_set
7
+ %i[
8
+ all_manager_uuids
9
+ arel
10
+ association
11
+ attributes_blacklist
12
+ attributes_whitelist
13
+ batch_extra_attributes
14
+ complete
15
+ create_only
16
+ custom_save_block
17
+ custom_reconnect_block
18
+ default_values
19
+ delete_method
20
+ dependency_attributes
21
+ check_changed
22
+ inventory_object_attributes
23
+ manager_ref
24
+ manager_ref_allowed_nil
25
+ manager_uuids
26
+ model_class
27
+ name
28
+ parent
29
+ parent_inventory_collections
30
+ retention_strategy
31
+ strategy
32
+ saver_strategy
33
+ secondary_refs
34
+ targeted
35
+ targeted_arel
36
+ update_only
37
+ use_ar_object
38
+ assert_graph_integrity
39
+ ].to_set
18
40
  end
19
41
 
20
42
  def allowed_properties
@@ -76,8 +98,8 @@ module InventoryRefresh
76
98
 
77
99
  send(@name.to_sym) if @name.respond_to?(:to_sym) && respond_to?(@name.to_sym)
78
100
 
79
- if @properties[:model_class].nil?
80
- add_properties(:model_class => auto_model_class) unless @options[:without_model_class]
101
+ if @properties[:model_class].nil? && !(@options[:without_model_class])
102
+ add_properties(:model_class => auto_model_class)
81
103
  end
82
104
  end
83
105
 
@@ -177,7 +199,7 @@ module InventoryRefresh
177
199
 
178
200
  def assert_allowed_property(name)
179
201
  unless allowed_properties.include?(name)
180
- raise "InventoryCollection property :#{name} is not allowed. Allowed properties are:\n#{self.allowed_properties.to_a.map(&:to_s).join(', ')}"
202
+ raise "InventoryCollection property :#{name} is not allowed. Allowed properties are:\n#{allowed_properties.to_a.map(&:to_s).join(', ')}"
181
203
  end
182
204
  end
183
205
 
@@ -216,7 +238,7 @@ module InventoryRefresh
216
238
  def auto_inventory_attributes
217
239
  return if @properties[:model_class].nil?
218
240
 
219
- (@properties[:model_class].new.methods - ar_base_class.methods).grep(/^[\w]+?\=$/).collect do |setter|
241
+ (@properties[:model_class].new.methods - ar_base_class.methods).grep(/^\w+?=$/).collect do |setter|
220
242
  setter.to_s[0..setter.length - 2].to_sym
221
243
  end
222
244
  end
@@ -70,6 +70,15 @@ module InventoryRefresh
70
70
  build(hash)
71
71
  end
72
72
 
73
+ # Finds InventoryObject.
74
+ #
75
+ # @param hash [Hash] Hash that needs to contain attributes defined in :manager_ref of the InventoryCollection
76
+ # @return [InventoryRefresh::InventoryObject] Found or built InventoryObject object
77
+ def find_in_data(hash)
78
+ _hash, _uuid, inventory_object = primary_index_scan(hash)
79
+ inventory_object
80
+ end
81
+
73
82
  # Finds of builds a new InventoryObject. By building it, we also put in into the InventoryCollection's storage.
74
83
  #
75
84
  # @param hash [Hash] Hash that needs to contain attributes defined in :manager_ref of the