lhs 24.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.bundler-version +1 -0
- data/.gitignore +39 -0
- data/.rubocop.localch.yml +325 -0
- data/.rubocop.yml +52 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Gemfile.activesupport4 +5 -0
- data/Gemfile.activesupport5 +4 -0
- data/LICENSE +674 -0
- data/README.md +2836 -0
- data/Rakefile +25 -0
- data/cider-ci.yml +6 -0
- data/cider-ci/bin/bundle +51 -0
- data/cider-ci/bin/ruby_install +8 -0
- data/cider-ci/bin/ruby_version +25 -0
- data/cider-ci/jobs/rspec-activesupport-4.yml +27 -0
- data/cider-ci/jobs/rspec-activesupport-5.yml +26 -0
- data/cider-ci/jobs/rspec-activesupport-latest.yml +24 -0
- data/cider-ci/jobs/rubocop.yml +18 -0
- data/cider-ci/task_components/bundle.yml +22 -0
- data/cider-ci/task_components/rspec.yml +37 -0
- data/cider-ci/task_components/rubocop.yml +29 -0
- data/cider-ci/task_components/ruby.yml +15 -0
- data/friday.yml +2 -0
- data/lhs.gemspec +43 -0
- data/lib/lhs.rb +100 -0
- data/lib/lhs/collection.rb +84 -0
- data/lib/lhs/complex.rb +158 -0
- data/lib/lhs/concerns/autoload_records.rb +55 -0
- data/lib/lhs/concerns/collection/handle_nested.rb +43 -0
- data/lib/lhs/concerns/collection/internal_collection.rb +49 -0
- data/lib/lhs/concerns/configuration.rb +20 -0
- data/lib/lhs/concerns/data/becomes.rb +18 -0
- data/lib/lhs/concerns/data/equality.rb +14 -0
- data/lib/lhs/concerns/data/json.rb +14 -0
- data/lib/lhs/concerns/data/to_hash.rb +14 -0
- data/lib/lhs/concerns/inspect.rb +70 -0
- data/lib/lhs/concerns/is_href.rb +15 -0
- data/lib/lhs/concerns/item/destroy.rb +38 -0
- data/lib/lhs/concerns/item/endpoint_lookup.rb +27 -0
- data/lib/lhs/concerns/item/save.rb +55 -0
- data/lib/lhs/concerns/item/update.rb +50 -0
- data/lib/lhs/concerns/item/validation.rb +61 -0
- data/lib/lhs/concerns/o_auth.rb +25 -0
- data/lib/lhs/concerns/option_blocks.rb +26 -0
- data/lib/lhs/concerns/proxy/accessors.rb +132 -0
- data/lib/lhs/concerns/proxy/create.rb +45 -0
- data/lib/lhs/concerns/proxy/link.rb +25 -0
- data/lib/lhs/concerns/proxy/problems.rb +27 -0
- data/lib/lhs/concerns/record/attribute_assignment.rb +25 -0
- data/lib/lhs/concerns/record/batch.rb +40 -0
- data/lib/lhs/concerns/record/chainable.rb +465 -0
- data/lib/lhs/concerns/record/configuration.rb +103 -0
- data/lib/lhs/concerns/record/create.rb +24 -0
- data/lib/lhs/concerns/record/custom_setters.rb +22 -0
- data/lib/lhs/concerns/record/destroy.rb +18 -0
- data/lib/lhs/concerns/record/endpoints.rb +108 -0
- data/lib/lhs/concerns/record/equality.rb +14 -0
- data/lib/lhs/concerns/record/find.rb +86 -0
- data/lib/lhs/concerns/record/find_by.rb +38 -0
- data/lib/lhs/concerns/record/first.rb +20 -0
- data/lib/lhs/concerns/record/href_for.rb +19 -0
- data/lib/lhs/concerns/record/last.rb +27 -0
- data/lib/lhs/concerns/record/mapping.rb +25 -0
- data/lib/lhs/concerns/record/merge.rb +26 -0
- data/lib/lhs/concerns/record/model.rb +23 -0
- data/lib/lhs/concerns/record/pagination.rb +47 -0
- data/lib/lhs/concerns/record/provider.rb +23 -0
- data/lib/lhs/concerns/record/relations.rb +26 -0
- data/lib/lhs/concerns/record/request.rb +620 -0
- data/lib/lhs/concerns/record/scope.rb +25 -0
- data/lib/lhs/concerns/record/tracing.rb +24 -0
- data/lib/lhs/concerns/record/update.rb +17 -0
- data/lib/lhs/config.rb +24 -0
- data/lib/lhs/data.rb +165 -0
- data/lib/lhs/endpoint.rb +12 -0
- data/lib/lhs/interceptors/auto_oauth/interceptor.rb +33 -0
- data/lib/lhs/interceptors/auto_oauth/thread_registry.rb +18 -0
- data/lib/lhs/interceptors/extended_rollbar/handler.rb +40 -0
- data/lib/lhs/interceptors/extended_rollbar/interceptor.rb +20 -0
- data/lib/lhs/interceptors/extended_rollbar/thread_registry.rb +19 -0
- data/lib/lhs/interceptors/request_cycle_cache/interceptor.rb +41 -0
- data/lib/lhs/interceptors/request_cycle_cache/thread_registry.rb +18 -0
- data/lib/lhs/item.rb +59 -0
- data/lib/lhs/pagination/base.rb +90 -0
- data/lib/lhs/pagination/link.rb +21 -0
- data/lib/lhs/pagination/offset.rb +22 -0
- data/lib/lhs/pagination/page.rb +18 -0
- data/lib/lhs/pagination/start.rb +22 -0
- data/lib/lhs/problems/base.rb +113 -0
- data/lib/lhs/problems/errors.rb +69 -0
- data/lib/lhs/problems/nested/base.rb +54 -0
- data/lib/lhs/problems/nested/errors.rb +16 -0
- data/lib/lhs/problems/nested/warnings.rb +15 -0
- data/lib/lhs/problems/warnings.rb +24 -0
- data/lib/lhs/proxy.rb +68 -0
- data/lib/lhs/railtie.rb +34 -0
- data/lib/lhs/record.rb +112 -0
- data/lib/lhs/rspec.rb +10 -0
- data/lib/lhs/test/stubbable_records.rb +34 -0
- data/lib/lhs/unprocessable.rb +6 -0
- data/lib/lhs/version.rb +5 -0
- data/script/ci/build.sh +18 -0
- data/spec/auto_oauth_spec.rb +169 -0
- data/spec/autoloading_spec.rb +48 -0
- data/spec/collection/accessors_spec.rb +31 -0
- data/spec/collection/collection_items_spec.rb +44 -0
- data/spec/collection/configurable_spec.rb +43 -0
- data/spec/collection/delegate_spec.rb +21 -0
- data/spec/collection/enumerable_spec.rb +27 -0
- data/spec/collection/href_spec.rb +17 -0
- data/spec/collection/meta_data_spec.rb +57 -0
- data/spec/collection/respond_to_spec.rb +20 -0
- data/spec/collection/to_a_spec.rb +34 -0
- data/spec/collection/to_ary_spec.rb +40 -0
- data/spec/collection/without_object_items_spec.rb +27 -0
- data/spec/complex/reduce_spec.rb +202 -0
- data/spec/concerns/record/request_spec.rb +78 -0
- data/spec/data/collection_spec.rb +56 -0
- data/spec/data/equality_spec.rb +23 -0
- data/spec/data/inspect_spec.rb +88 -0
- data/spec/data/is_item_or_collection_spec.rb +40 -0
- data/spec/data/item_spec.rb +106 -0
- data/spec/data/merge_spec.rb +27 -0
- data/spec/data/parent_spec.rb +39 -0
- data/spec/data/raw_spec.rb +48 -0
- data/spec/data/respond_to_spec.rb +26 -0
- data/spec/data/root_spec.rb +25 -0
- data/spec/data/select_spec.rb +27 -0
- data/spec/data/to_ary_spec.rb +28 -0
- data/spec/data/to_json_spec.rb +68 -0
- data/spec/dummy/Rakefile +8 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +26 -0
- data/spec/dummy/app/controllers/automatic_authentication_controller.rb +29 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/controllers/error_handling_with_chains_controller.rb +36 -0
- data/spec/dummy/app/controllers/extended_rollbar_controller.rb +10 -0
- data/spec/dummy/app/controllers/option_blocks_controller.rb +15 -0
- data/spec/dummy/app/controllers/request_cycle_cache_controller.rb +27 -0
- data/spec/dummy/app/helpers/application_helper.rb +4 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/dummy_customer.rb +6 -0
- data/spec/dummy/app/models/dummy_record.rb +6 -0
- data/spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb +6 -0
- data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb +7 -0
- data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb +7 -0
- data/spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb +6 -0
- data/spec/dummy/app/models/dummy_record_with_oauth.rb +7 -0
- data/spec/dummy/app/models/dummy_user.rb +6 -0
- data/spec/dummy/app/models/providers/customer_system.rb +7 -0
- data/spec/dummy/app/models/providers/internal_services.rb +7 -0
- data/spec/dummy/app/views/error_handling_with_chains/error.html.erb +1 -0
- data/spec/dummy/app/views/error_handling_with_chains/show.html.erb +3 -0
- data/spec/dummy/app/views/form_for.html.erb +5 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +5 -0
- data/spec/dummy/bin/rails +6 -0
- data/spec/dummy/bin/rake +6 -0
- data/spec/dummy/config.ru +6 -0
- data/spec/dummy/config/application.rb +16 -0
- data/spec/dummy/config/boot.rb +7 -0
- data/spec/dummy/config/environment.rb +7 -0
- data/spec/dummy/config/environments/development.rb +36 -0
- data/spec/dummy/config/environments/production.rb +77 -0
- data/spec/dummy/config/environments/test.rb +40 -0
- data/spec/dummy/config/initializers/assets.rb +10 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
- data/spec/dummy/config/initializers/inflections.rb +18 -0
- data/spec/dummy/config/initializers/mime_types.rb +6 -0
- data/spec/dummy/config/initializers/rollbar.rb +9 -0
- data/spec/dummy/config/initializers/session_store.rb +5 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +27 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/endpoint/for_url_spec.rb +27 -0
- data/spec/extended_rollbar_spec.rb +67 -0
- data/spec/item/access_errors_spec.rb +33 -0
- data/spec/item/accessors_spec.rb +21 -0
- data/spec/item/add_error_spec.rb +21 -0
- data/spec/item/becomes_spec.rb +38 -0
- data/spec/item/blacklisted_keywords_spec.rb +30 -0
- data/spec/item/delegate_spec.rb +32 -0
- data/spec/item/destroy_spec.rb +113 -0
- data/spec/item/dig_spec.rb +29 -0
- data/spec/item/error_codes_spec.rb +55 -0
- data/spec/item/errors_spec.rb +324 -0
- data/spec/item/fetch_spec.rb +39 -0
- data/spec/item/getter_spec.rb +24 -0
- data/spec/item/internal_data_structure_spec.rb +37 -0
- data/spec/item/map_spec.rb +46 -0
- data/spec/item/nested_errors_spec.rb +28 -0
- data/spec/item/partial_update_spec.rb +170 -0
- data/spec/item/respond_to_spec.rb +31 -0
- data/spec/item/save_spec.rb +115 -0
- data/spec/item/setter_spec.rb +44 -0
- data/spec/item/translate_errors_spec.rb +257 -0
- data/spec/item/update_spec.rb +161 -0
- data/spec/item/validation_spec.rb +131 -0
- data/spec/item/warning_codes_spec.rb +55 -0
- data/spec/item/warnings_spec.rb +52 -0
- data/spec/option_blocks/ensure_reset_between_requests_spec.rb +23 -0
- data/spec/option_blocks/main_spec.rb +55 -0
- data/spec/pagination/link/current_page_spec.rb +19 -0
- data/spec/pagination/link/pages_left_spec.rb +36 -0
- data/spec/pagination/link/parallel_spec.rb +19 -0
- data/spec/pagination/link/total_spec.rb +46 -0
- data/spec/pagination/offset/pages_left_spec.rb +26 -0
- data/spec/pagination/parameters_spec.rb +61 -0
- data/spec/proxy/create_sub_resource_spec.rb +182 -0
- data/spec/proxy/load_spec.rb +75 -0
- data/spec/proxy/record_identification_spec.rb +35 -0
- data/spec/rails_helper.rb +13 -0
- data/spec/record/all_spec.rb +133 -0
- data/spec/record/attribute_assignment_spec.rb +28 -0
- data/spec/record/build_spec.rb +26 -0
- data/spec/record/cast_nested_data_spec.rb +78 -0
- data/spec/record/create_spec.rb +160 -0
- data/spec/record/creation_failed_spec.rb +55 -0
- data/spec/record/custom_setters_spec.rb +45 -0
- data/spec/record/definitions_spec.rb +29 -0
- data/spec/record/destroy_spec.rb +38 -0
- data/spec/record/dig_configuration_spec.rb +75 -0
- data/spec/record/dup_spec.rb +20 -0
- data/spec/record/endpoint_inheritance_spec.rb +65 -0
- data/spec/record/endpoint_options_spec.rb +52 -0
- data/spec/record/endpoint_priorities_spec.rb +26 -0
- data/spec/record/endpoints_spec.rb +96 -0
- data/spec/record/equality_spec.rb +27 -0
- data/spec/record/error_handling_integration_spec.rb +25 -0
- data/spec/record/error_handling_spec.rb +40 -0
- data/spec/record/expanded_spec.rb +69 -0
- data/spec/record/fetch_spec.rb +41 -0
- data/spec/record/find_by_chains_spec.rb +21 -0
- data/spec/record/find_by_spec.rb +76 -0
- data/spec/record/find_each_spec.rb +57 -0
- data/spec/record/find_in_batches_spec.rb +122 -0
- data/spec/record/find_in_parallel_spec.rb +67 -0
- data/spec/record/find_spec.rb +104 -0
- data/spec/record/first_spec.rb +39 -0
- data/spec/record/force_merge_spec.rb +56 -0
- data/spec/record/handle_includes_errors_spec.rb +32 -0
- data/spec/record/has_many_spec.rb +120 -0
- data/spec/record/has_one_spec.rb +116 -0
- data/spec/record/href_for_spec.rb +25 -0
- data/spec/record/ignore_errors_spec.rb +139 -0
- data/spec/record/immutable_chains_spec.rb +22 -0
- data/spec/record/includes_first_page_spec.rb +737 -0
- data/spec/record/includes_spec.rb +693 -0
- data/spec/record/includes_warning_spec.rb +46 -0
- data/spec/record/item_key_spec.rb +81 -0
- data/spec/record/items_created_key_configuration_spec.rb +37 -0
- data/spec/record/last_spec.rb +68 -0
- data/spec/record/loading_twice_spec.rb +19 -0
- data/spec/record/mapping_spec.rb +102 -0
- data/spec/record/model_name_spec.rb +17 -0
- data/spec/record/new_spec.rb +106 -0
- data/spec/record/options_getter_spec.rb +26 -0
- data/spec/record/options_spec.rb +164 -0
- data/spec/record/paginatable_collection_spec.rb +360 -0
- data/spec/record/pagination_chain_spec.rb +101 -0
- data/spec/record/pagination_links_spec.rb +72 -0
- data/spec/record/pagination_spec.rb +71 -0
- data/spec/record/persisted_spec.rb +52 -0
- data/spec/record/provider_spec.rb +41 -0
- data/spec/record/references_spec.rb +53 -0
- data/spec/record/relation_caching_spec.rb +121 -0
- data/spec/record/reload_by_id_spec.rb +43 -0
- data/spec/record/reload_spec.rb +65 -0
- data/spec/record/request_spec.rb +90 -0
- data/spec/record/save_spec.rb +40 -0
- data/spec/record/scope_chains_spec.rb +39 -0
- data/spec/record/select_spec.rb +17 -0
- data/spec/record/to_ary_spec.rb +65 -0
- data/spec/record/to_hash_spec.rb +22 -0
- data/spec/record/to_json_spec.rb +22 -0
- data/spec/record/tracing_spec.rb +154 -0
- data/spec/record/update_spec.rb +62 -0
- data/spec/record/where_chains_spec.rb +57 -0
- data/spec/record/where_spec.rb +62 -0
- data/spec/record/where_values_hash_spec.rb +32 -0
- data/spec/request_cycle_cache_spec.rb +106 -0
- data/spec/require_lhs_spec.rb +9 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/stubs/all_spec.rb +72 -0
- data/spec/support/fixtures/json/feedback.json +11 -0
- data/spec/support/fixtures/json/feedbacks.json +174 -0
- data/spec/support/fixtures/json/localina_content_ad.json +23 -0
- data/spec/support/load_json.rb +5 -0
- data/spec/support/request_cycle_cache.rb +10 -0
- data/spec/support/reset.rb +67 -0
- data/spec/views/form_for_spec.rb +20 -0
- metadata +776 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# A collection is a special type of data
|
|
4
|
+
# that contains multiple items
|
|
5
|
+
class LHS::Collection < LHS::Proxy
|
|
6
|
+
autoload :HandleNested,
|
|
7
|
+
'lhs/concerns/collection/handle_nested'
|
|
8
|
+
autoload :InternalCollection,
|
|
9
|
+
'lhs/concerns/collection/internal_collection'
|
|
10
|
+
|
|
11
|
+
include HandleNested
|
|
12
|
+
include InternalCollection
|
|
13
|
+
include Create
|
|
14
|
+
|
|
15
|
+
METHOD_NAMES_EXLCUDED_FROM_WRAPPING = %w(to_a to_ary map).freeze
|
|
16
|
+
|
|
17
|
+
delegate :select, :length, :size, to: :_collection
|
|
18
|
+
delegate :_record, :_raw, to: :_data
|
|
19
|
+
delegate :limit, :count, :total, :offset, :current_page, :start,
|
|
20
|
+
:next?, :previous?, to: :_pagination
|
|
21
|
+
|
|
22
|
+
def _pagination
|
|
23
|
+
_record.pagination(_data)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def href
|
|
27
|
+
return _data._raw[:href] if _data._raw.is_a? Hash
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def _collection
|
|
32
|
+
@_collection ||= begin
|
|
33
|
+
raw = _data._raw if _data._raw.is_a?(Array)
|
|
34
|
+
raw ||= _data.access(input: _data._raw, record: _record)
|
|
35
|
+
Collection.new(raw, _data, _record)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def collection?
|
|
40
|
+
true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def item?
|
|
44
|
+
false
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def raw_items
|
|
48
|
+
if _raw.is_a?(Array)
|
|
49
|
+
_raw
|
|
50
|
+
else
|
|
51
|
+
access(input: _raw, record: _record)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
protected
|
|
56
|
+
|
|
57
|
+
def method_missing(name, *args, &block)
|
|
58
|
+
if _collection.respond_to?(name)
|
|
59
|
+
value = _collection.send(name, *args, &block)
|
|
60
|
+
record = LHS::Record.for_url(value[:href]) if value.is_a?(Hash) && value[:href]
|
|
61
|
+
record ||= _record
|
|
62
|
+
value = enclose_item_in_data(value) if value.is_a?(Hash)
|
|
63
|
+
return value if METHOD_NAMES_EXLCUDED_FROM_WRAPPING.include?(name.to_s)
|
|
64
|
+
wrap_return(value, record, name, args)
|
|
65
|
+
elsif _data._raw.is_a?(Hash)
|
|
66
|
+
get(name, *args)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def respond_to_missing?(name, _include_all = false)
|
|
71
|
+
# We accept every message that does not belong to set of keywords and is not a setter
|
|
72
|
+
!BLACKLISTED_KEYWORDS.include?(name.to_s) && !name.to_s[/=$/]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
# Encloses accessed collection item
|
|
78
|
+
# by wrapping it in an LHS::Item
|
|
79
|
+
def enclose_item_in_data(value)
|
|
80
|
+
data = LHS::Data.new(value, _data, _record)
|
|
81
|
+
item = LHS::Item.new(data)
|
|
82
|
+
LHS::Data.new(item, _data)
|
|
83
|
+
end
|
|
84
|
+
end
|
data/lib/lhs/complex.rb
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Complex is the main data structure for includes:
|
|
4
|
+
# Can be for example :place, [:place, :customer],
|
|
5
|
+
# [{ places: [:customer] }, { places: { customer: :contract }}]
|
|
6
|
+
# and so on
|
|
7
|
+
class LHS::Complex
|
|
8
|
+
attr_reader :data
|
|
9
|
+
|
|
10
|
+
def reduce!(data)
|
|
11
|
+
if data.is_a?(LHS::Complex)
|
|
12
|
+
@data = data.data
|
|
13
|
+
elsif data.is_a?(Array) && !data.empty?
|
|
14
|
+
@data = data.inject(LHS::Complex.new.reduce!([])) { |acc, datum| acc.merge!(LHS::Complex.new.reduce!(datum)) }.data
|
|
15
|
+
elsif data.is_a?(Hash) && !data.empty?
|
|
16
|
+
@data = data.map { |k, v| [k, LHS::Complex.new.reduce!(v)] }.to_h
|
|
17
|
+
else
|
|
18
|
+
@data = data
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
self
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.reduce(data)
|
|
25
|
+
new.reduce!(data).unwrap
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def merge!(other)
|
|
29
|
+
if data.is_a?(Symbol)
|
|
30
|
+
merge_into_symbol!(other)
|
|
31
|
+
elsif data.is_a?(Array)
|
|
32
|
+
merge_into_array!(other)
|
|
33
|
+
elsif data.is_a?(Hash)
|
|
34
|
+
merge_into_hash!(other)
|
|
35
|
+
elsif unwrap != other.unwrap
|
|
36
|
+
raise ArgumentError, "Cannot merge #{unwrap} with #{other.unwrap}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
self
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def unwrap
|
|
43
|
+
if data.is_a?(Array)
|
|
44
|
+
result = data.map(&:unwrap)
|
|
45
|
+
result.empty? ? nil : result
|
|
46
|
+
elsif data.is_a?(Hash)
|
|
47
|
+
result = data.map { |k, v| [k, v.unwrap] }.to_h
|
|
48
|
+
result.empty? ? nil : result
|
|
49
|
+
else
|
|
50
|
+
data
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def ==(other)
|
|
55
|
+
unwrap == other.unwrap
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def merge_into_array!(other)
|
|
61
|
+
if data.empty?
|
|
62
|
+
@data = other.data
|
|
63
|
+
elsif other.data.is_a?(Symbol)
|
|
64
|
+
merge_symbol_into_array!(other)
|
|
65
|
+
elsif other.data.is_a?(Array)
|
|
66
|
+
merge_array_into_array!(other)
|
|
67
|
+
elsif other.data.is_a?(Hash)
|
|
68
|
+
merge_hash_into_array!(other)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def merge_symbol_into_array!(other)
|
|
73
|
+
return if data.include?(other)
|
|
74
|
+
data.push(other)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def merge_array_into_array!(other)
|
|
78
|
+
@data = other.data.inject(self) { |acc, datum| acc.merge!(datum) }.data
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def merge_hash_into_array!(other)
|
|
82
|
+
@data = [].tap do |new_data|
|
|
83
|
+
data.each do |element|
|
|
84
|
+
if element.data.is_a?(Symbol)
|
|
85
|
+
# remove keys that were in the hash
|
|
86
|
+
new_data << element if !other.data.key?(element.data)
|
|
87
|
+
elsif element.data.is_a?(Array)
|
|
88
|
+
new_data << element
|
|
89
|
+
elsif element.data.is_a?(Hash)
|
|
90
|
+
new_data << element.merge!(other)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# add it to the array if there was no hash to merge it
|
|
96
|
+
data.push(other) if data.none? { |element| element.data.is_a?(Hash) }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def merge_into_hash!(other)
|
|
100
|
+
if data.empty?
|
|
101
|
+
@data = other.data
|
|
102
|
+
elsif other.data.is_a?(Symbol)
|
|
103
|
+
merge_symbol_into_hash!(other)
|
|
104
|
+
elsif other.data.is_a?(Array)
|
|
105
|
+
merge_array_into_hash!(other)
|
|
106
|
+
elsif other.data.is_a?(Hash)
|
|
107
|
+
merge_hash_into_hash!(other)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def merge_symbol_into_hash!(other)
|
|
112
|
+
return if data.key?(other.data)
|
|
113
|
+
|
|
114
|
+
@data = [LHS::Complex.new.reduce!(data), other]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def merge_array_into_hash!(other)
|
|
118
|
+
@data = other.data.inject(self) { |acc, datum| acc.merge!(datum) }.data
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def merge_hash_into_hash!(other)
|
|
122
|
+
other.data.each do |k, v|
|
|
123
|
+
if data.key?(k)
|
|
124
|
+
data[k] = data[k].merge!(v)
|
|
125
|
+
else
|
|
126
|
+
data[k] = v
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def merge_into_symbol!(other)
|
|
132
|
+
if other.data.is_a?(Symbol)
|
|
133
|
+
merge_symbol_into_symbol!(other)
|
|
134
|
+
elsif other.data.is_a?(Array)
|
|
135
|
+
merge_array_into_symbol!(other)
|
|
136
|
+
elsif other.data.is_a?(Hash)
|
|
137
|
+
merge_hash_into_symbol!(other)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def merge_symbol_into_symbol!(other)
|
|
142
|
+
return if other.data == data
|
|
143
|
+
|
|
144
|
+
@data = [LHS::Complex.new.reduce!(data), other]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def merge_array_into_symbol!(other)
|
|
148
|
+
@data = other.data.unshift(LHS::Complex.new.reduce!(data)).uniq { |a| a.unwrap }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def merge_hash_into_symbol!(other)
|
|
152
|
+
if other.data.key?(data)
|
|
153
|
+
@data = other.data
|
|
154
|
+
else
|
|
155
|
+
@data = [LHS::Complex.new.reduce!(data), other]
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support'
|
|
4
|
+
|
|
5
|
+
# Preload all the LHS::Records that are defined in app/models/*
|
|
6
|
+
# in order to collect record endpoints and to be able to identify records from hrefs
|
|
7
|
+
# and not only from model constant names (which is different to ActiveRecord)
|
|
8
|
+
module AutoloadRecords
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
included do
|
|
12
|
+
class Engine < Rails::Engine
|
|
13
|
+
initializer 'Load all LHS::Records from app/models/**' do |app|
|
|
14
|
+
Middleware.require_records
|
|
15
|
+
next if app.config.cache_classes
|
|
16
|
+
|
|
17
|
+
app.config.middleware.use Middleware
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Middleware
|
|
21
|
+
def initialize(app)
|
|
22
|
+
@app = app
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def call(env)
|
|
26
|
+
self.class.require_records
|
|
27
|
+
@app.call(env)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.model_files
|
|
31
|
+
Dir.glob(Rails.root.join('app', 'models', '**', '*.rb'))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.require_direct_inheritance
|
|
35
|
+
model_files.map do |file|
|
|
36
|
+
next unless File.read(file).match('LHS::Record')
|
|
37
|
+
require_dependency file
|
|
38
|
+
file.split('models/').last.gsub('.rb', '').classify
|
|
39
|
+
end.compact
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.require_inheriting_records(parents)
|
|
43
|
+
model_files.each do |file|
|
|
44
|
+
next if parents.none? { |parent| File.read(file).match(parent) }
|
|
45
|
+
require_dependency file
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.require_records
|
|
50
|
+
require_inheriting_records(require_direct_inheritance)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support'
|
|
4
|
+
|
|
5
|
+
class LHS::Collection < LHS::Proxy
|
|
6
|
+
|
|
7
|
+
# Handles pontentially (deep-)nested collections
|
|
8
|
+
# Examples:
|
|
9
|
+
# [ { name: 'Steve '} ]
|
|
10
|
+
# { items: [ { name: 'Steve' } ] }
|
|
11
|
+
# { response: { business: [ { name: 'Steve' } ] } }
|
|
12
|
+
module HandleNested
|
|
13
|
+
extend ActiveSupport::Concern
|
|
14
|
+
|
|
15
|
+
delegate :access, :nest, :concat, to: :class
|
|
16
|
+
|
|
17
|
+
module ClassMethods
|
|
18
|
+
# Access potentially nested collection of items
|
|
19
|
+
def access(input:, record: nil)
|
|
20
|
+
input.dig(*items_key(record))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Initializes nested collection
|
|
24
|
+
def nest(input:, value: nil, record: nil)
|
|
25
|
+
input[items_key(record)] = value
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Concats existing nested collection of items
|
|
29
|
+
# with given items
|
|
30
|
+
def concat(input:, items:, record: nil)
|
|
31
|
+
input.dig(*items_key(record)).concat(items)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# Takes configured items key to access collection of items
|
|
37
|
+
# of falls back to the default key
|
|
38
|
+
def items_key(record)
|
|
39
|
+
record&.items_key || LHS::Record.items_key
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support'
|
|
4
|
+
|
|
5
|
+
class LHS::Collection < LHS::Proxy
|
|
6
|
+
|
|
7
|
+
module InternalCollection
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
# The internal collection class that includes enumerable
|
|
11
|
+
# and insures to return LHS::Items in case of iterating items
|
|
12
|
+
class Collection
|
|
13
|
+
include Enumerable
|
|
14
|
+
|
|
15
|
+
attr_accessor :raw
|
|
16
|
+
delegate :length, :size, :first, :last, :sample, :[], :present?, :blank?, :empty?,
|
|
17
|
+
:<<, :push, :compact, to: :raw
|
|
18
|
+
|
|
19
|
+
def initialize(raw, parent, record)
|
|
20
|
+
self.raw = raw
|
|
21
|
+
@parent = parent
|
|
22
|
+
@record = record
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_ary
|
|
26
|
+
map { |item| item }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def each(&_block)
|
|
30
|
+
raw.each do |item|
|
|
31
|
+
if item.is_a? Hash
|
|
32
|
+
yield cast_item(item)
|
|
33
|
+
else
|
|
34
|
+
yield item
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def cast_item(item)
|
|
42
|
+
record_by_href = LHS::Record.for_url(item[:href]) if item[:href]
|
|
43
|
+
data = LHS::Data.new(item, @parent, @record)
|
|
44
|
+
return (record_by_href || @record).new(data) if record_by_href || @record
|
|
45
|
+
data
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support'
|
|
4
|
+
|
|
5
|
+
module LHS
|
|
6
|
+
module Configuration
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def config
|
|
11
|
+
LHS::Config.instance
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def configure
|
|
15
|
+
LHS::Config.instance.reset
|
|
16
|
+
yield config
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support'
|
|
4
|
+
|
|
5
|
+
class LHS::Data
|
|
6
|
+
|
|
7
|
+
module Becomes
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
def becomes(klass, options = {})
|
|
11
|
+
return self if self.class == klass && !is_a?(LHS::Data)
|
|
12
|
+
data = LHS::Data.new(_raw, _parent, klass)
|
|
13
|
+
data.errors = options[:errors] if options[:errors]
|
|
14
|
+
data.warnings = options[:warnings] if options[:warnings]
|
|
15
|
+
klass.new(data)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|