datashift 0.16.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/{LICENSE.txt → LICENSE} +0 -0
- data/Rakefile +1 -20
- data/datashift.thor +125 -0
- data/lib/applications/apache_poi_extensions.rb +21 -52
- data/lib/applications/excel.rb +64 -57
- data/lib/applications/hssf_row_extensions.rb +66 -0
- data/lib/applications/jexcel_file.rb +99 -95
- data/lib/applications/jexcel_file_extensions.rb +76 -83
- data/lib/applications/jruby/word.rb +36 -36
- data/lib/applications/ruby_poi_translations.rb +34 -32
- data/lib/applications/spreadsheet_extensions.rb +21 -19
- data/lib/datashift.rb +49 -59
- data/lib/datashift/binder.rb +217 -0
- data/lib/datashift/column_packer.rb +21 -72
- data/lib/datashift/configuration.rb +317 -0
- data/lib/datashift/context_factory.rb +88 -0
- data/lib/datashift/core_ext/array.rb +15 -0
- data/lib/datashift/core_ext/csv_ext.rb +46 -0
- data/lib/datashift/core_ext/string.rb +49 -0
- data/lib/datashift/core_ext/to_b.rb +11 -0
- data/lib/datashift/delimiters.rb +55 -61
- data/lib/datashift/doc_context.rb +137 -0
- data/lib/datashift/excel_base.rb +93 -81
- data/lib/datashift/exceptions.rb +30 -28
- data/lib/datashift/file_definitions.rb +44 -39
- data/lib/datashift/guards.rb +5 -5
- data/lib/datashift/header.rb +25 -0
- data/lib/datashift/headers.rb +94 -0
- data/lib/datashift/inbound_data/column.rb +44 -0
- data/lib/datashift/inbound_data/lookup_support.rb +33 -0
- data/lib/datashift/inbound_data/method_binding.rb +139 -0
- data/lib/datashift/load_object.rb +37 -12
- data/lib/datashift/logging.rb +54 -27
- data/lib/datashift/mandatory.rb +39 -0
- data/lib/datashift/mapping/data_flow_schema.rb +198 -0
- data/lib/datashift/{model_mapper.rb → mapping/mapper_utils.rb} +30 -10
- data/lib/datashift/model_methods/catalogue.rb +183 -0
- data/lib/datashift/model_methods/collection.rb +140 -0
- data/lib/datashift/model_methods/model_method.rb +162 -0
- data/lib/datashift/model_methods/model_methods_manager.rb +76 -0
- data/lib/datashift/model_methods/operator.rb +62 -0
- data/lib/datashift/node_collection.rb +26 -0
- data/lib/datashift/node_context.rb +68 -0
- data/lib/datashift/populator.rb +308 -282
- data/lib/datashift/progress_monitor.rb +91 -0
- data/lib/datashift/querying.rb +110 -52
- data/lib/datashift/templates/import_export_config.erb +55 -0
- data/lib/datashift/transformation/factory.rb +219 -0
- data/lib/datashift/transformation/remove.rb +44 -0
- data/lib/datashift/version.rb +3 -0
- data/lib/exporters/configuration.rb +84 -0
- data/lib/exporters/csv_exporter.rb +54 -52
- data/lib/exporters/excel_exporter.rb +80 -61
- data/lib/exporters/exporter_base.rb +8 -8
- data/lib/generators/config_generator.rb +218 -0
- data/lib/generators/csv_generator.rb +13 -70
- data/lib/generators/excel_generator.rb +23 -111
- data/lib/generators/generator_base.rb +15 -70
- data/lib/loaders/configuration.rb +90 -0
- data/lib/loaders/csv_loader.rb +63 -101
- data/lib/loaders/excel_loader.rb +71 -156
- data/lib/loaders/failure_data.rb +40 -0
- data/lib/loaders/file_loader.rb +16 -0
- data/lib/loaders/loader_base.rb +82 -410
- data/lib/loaders/loader_factory.rb +42 -0
- data/lib/loaders/paperclip/attachment_loader.rb +157 -140
- data/lib/loaders/paperclip/datashift_paperclip.rb +18 -35
- data/lib/loaders/paperclip/image_loading.rb +40 -35
- data/lib/loaders/reporters/basic_stdout_reporter.rb +40 -0
- data/lib/loaders/reporters/reporter.rb +26 -0
- data/lib/tasks/config.thor +65 -0
- data/{tasks → lib/tasks}/config/seed_fu_product_template.erb +0 -0
- data/{tasks → lib/tasks}/config/tidy_config.txt +0 -0
- data/lib/tasks/export.thor +192 -0
- data/lib/tasks/generate.thor +190 -0
- data/lib/tasks/import.thor +142 -0
- data/lib/{thor → tasks}/paperclip.thor +69 -69
- data/{tasks → lib/tasks/to_convert_to_thor}/db_tasks.rake +20 -20
- data/lib/tasks/tools.thor +109 -0
- data/spec/MissingAttachmentRecords/DEMO_001_ror_bag.jpeg +0 -0
- data/spec/MissingAttachmentRecords/DEMO_002_Powerstation.jpeg +0 -0
- data/spec/MissingAttachmentRecords/DEMO_003_ror_mug.jpeg +0 -0
- data/spec/MissingAttachmentRecords/DEMO_004_ror_ringer.jpeg +0 -0
- data/spec/datashift/binder_spec.rb +266 -0
- data/spec/datashift/config_generator_spec.rb +186 -0
- data/spec/datashift/configuration.rb +66 -0
- data/spec/datashift/context_factory_spec.rb +63 -0
- data/spec/datashift/data_flow_schema_spec.rb +150 -0
- data/spec/datashift/datashift_spec.rb +52 -0
- data/spec/datashift/excel_base_spec.rb +57 -0
- data/spec/datashift/excel_spec.rb +188 -0
- data/spec/datashift/failure_data_spec.rb +27 -0
- data/spec/{file_definitions.rb → datashift/file_definitions.rb} +9 -10
- data/spec/datashift/headers_spec.rb +56 -0
- data/spec/datashift/inbound_data_spec.rb +47 -0
- data/spec/datashift/mapper_utils_spec.rb +38 -0
- data/spec/datashift/method_binding_spec.rb +60 -0
- data/spec/datashift/model_method_spec.rb +109 -0
- data/spec/datashift/model_methods_catalogue.rb +111 -0
- data/spec/datashift/model_methods_collection_spec.rb +138 -0
- data/spec/datashift/model_methods_manager_spec.rb +329 -0
- data/spec/datashift/populator_spec.rb +117 -0
- data/spec/datashift/thor_spec.rb +314 -0
- data/spec/datashift/transformation/factory_spec.rb +195 -0
- data/spec/datashift/transformation/transformer_remove_spec.rb +43 -0
- data/spec/dummy/Gemfile +53 -0
- data/spec/dummy/Gemfile.lock +197 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +16 -0
- data/spec/dummy/app/assets/javascripts/categories.js +2 -0
- data/spec/dummy/app/assets/javascripts/digitals.js +2 -0
- data/spec/dummy/app/assets/javascripts/empties.js +2 -0
- data/spec/dummy/app/assets/javascripts/loader_releases.js +2 -0
- data/spec/dummy/app/assets/javascripts/long_and_complex_table_linked_to_versions.js +2 -0
- data/spec/dummy/app/assets/javascripts/milestones.js +2 -0
- data/spec/dummy/app/assets/javascripts/owners.js +2 -0
- data/spec/dummy/app/assets/javascripts/projects.js +2 -0
- data/spec/dummy/app/assets/javascripts/users.js +2 -0
- data/spec/dummy/app/assets/javascripts/versions.js +2 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/assets/stylesheets/categories.css +4 -0
- data/spec/dummy/app/assets/stylesheets/digitals.css +4 -0
- data/spec/dummy/app/assets/stylesheets/empties.css +4 -0
- data/spec/dummy/app/assets/stylesheets/loader_releases.css +4 -0
- data/spec/dummy/app/assets/stylesheets/long_and_complex_table_linked_to_versions.css +4 -0
- data/spec/dummy/app/assets/stylesheets/milestones.css +4 -0
- data/spec/dummy/app/assets/stylesheets/owners.css +4 -0
- data/spec/dummy/app/assets/stylesheets/projects.css +4 -0
- data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/spec/dummy/app/assets/stylesheets/users.css +4 -0
- data/spec/dummy/app/assets/stylesheets/versions.css +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/categories_controller.rb +58 -0
- data/spec/dummy/app/controllers/digitals_controller.rb +58 -0
- data/spec/dummy/app/controllers/empties_controller.rb +58 -0
- data/spec/dummy/app/controllers/loader_releases_controller.rb +58 -0
- data/spec/dummy/app/controllers/long_and_complex_table_linked_to_versions_controller.rb +58 -0
- data/spec/dummy/app/controllers/milestones_controller.rb +58 -0
- data/spec/dummy/app/controllers/owners_controller.rb +58 -0
- data/spec/dummy/app/controllers/projects_controller.rb +58 -0
- data/spec/dummy/app/controllers/users_controller.rb +58 -0
- data/spec/dummy/app/controllers/versions_controller.rb +58 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/categories_helper.rb +2 -0
- data/spec/dummy/app/helpers/digitals_helper.rb +2 -0
- data/spec/dummy/app/helpers/empties_helper.rb +2 -0
- data/spec/dummy/app/helpers/loader_releases_helper.rb +2 -0
- data/spec/dummy/app/helpers/long_and_complex_table_linked_to_versions_helper.rb +2 -0
- data/spec/dummy/app/helpers/milestones_helper.rb +2 -0
- data/spec/dummy/app/helpers/owners_helper.rb +2 -0
- data/spec/dummy/app/helpers/projects_helper.rb +2 -0
- data/spec/dummy/app/helpers/users_helper.rb +2 -0
- data/spec/dummy/app/helpers/versions_helper.rb +2 -0
- data/spec/dummy/app/models/category.rb +6 -0
- data/spec/dummy/app/models/digital.rb +22 -0
- data/spec/dummy/app/models/empty.rb +2 -0
- data/spec/dummy/app/models/loader_release.rb +10 -0
- data/spec/dummy/app/models/long_and_complex_table_linked_to_version.rb +6 -0
- data/spec/dummy/app/models/milestone.rb +15 -0
- data/spec/dummy/app/models/owner.rb +13 -0
- data/spec/dummy/app/models/project.rb +53 -0
- data/spec/dummy/app/models/user.rb +5 -0
- data/spec/dummy/app/models/version.rb +7 -0
- data/spec/dummy/app/views/categories/_form.html.erb +17 -0
- data/spec/dummy/app/views/categories/edit.html.erb +6 -0
- data/spec/dummy/app/views/categories/index.html.erb +25 -0
- data/spec/dummy/app/views/categories/new.html.erb +5 -0
- data/spec/dummy/app/views/categories/show.html.erb +4 -0
- data/spec/dummy/app/views/digitals/_form.html.erb +17 -0
- data/spec/dummy/app/views/digitals/edit.html.erb +6 -0
- data/spec/dummy/app/views/digitals/index.html.erb +25 -0
- data/spec/dummy/app/views/digitals/new.html.erb +5 -0
- data/spec/dummy/app/views/digitals/show.html.erb +4 -0
- data/spec/dummy/app/views/empties/_form.html.erb +17 -0
- data/spec/dummy/app/views/empties/edit.html.erb +6 -0
- data/spec/dummy/app/views/empties/index.html.erb +25 -0
- data/spec/dummy/app/views/empties/new.html.erb +5 -0
- data/spec/dummy/app/views/empties/show.html.erb +4 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/loader_releases/_form.html.erb +17 -0
- data/spec/dummy/app/views/loader_releases/edit.html.erb +6 -0
- data/spec/dummy/app/views/loader_releases/index.html.erb +25 -0
- data/spec/dummy/app/views/loader_releases/new.html.erb +5 -0
- data/spec/dummy/app/views/loader_releases/show.html.erb +4 -0
- data/spec/dummy/app/views/long_and_complex_table_linked_to_versions/_form.html.erb +17 -0
- data/spec/dummy/app/views/long_and_complex_table_linked_to_versions/edit.html.erb +6 -0
- data/spec/dummy/app/views/long_and_complex_table_linked_to_versions/index.html.erb +25 -0
- data/spec/dummy/app/views/long_and_complex_table_linked_to_versions/new.html.erb +5 -0
- data/spec/dummy/app/views/long_and_complex_table_linked_to_versions/show.html.erb +4 -0
- data/spec/dummy/app/views/milestones/_form.html.erb +17 -0
- data/spec/dummy/app/views/milestones/edit.html.erb +6 -0
- data/spec/dummy/app/views/milestones/index.html.erb +25 -0
- data/spec/dummy/app/views/milestones/new.html.erb +5 -0
- data/spec/dummy/app/views/milestones/show.html.erb +4 -0
- data/spec/dummy/app/views/owners/_form.html.erb +17 -0
- data/spec/dummy/app/views/owners/edit.html.erb +6 -0
- data/spec/dummy/app/views/owners/index.html.erb +25 -0
- data/spec/dummy/app/views/owners/new.html.erb +5 -0
- data/spec/dummy/app/views/owners/show.html.erb +4 -0
- data/spec/dummy/app/views/projects/_form.html.erb +17 -0
- data/spec/dummy/app/views/projects/edit.html.erb +6 -0
- data/spec/dummy/app/views/projects/index.html.erb +25 -0
- data/spec/dummy/app/views/projects/new.html.erb +5 -0
- data/spec/dummy/app/views/projects/show.html.erb +4 -0
- data/spec/dummy/app/views/users/_form.html.erb +17 -0
- data/spec/dummy/app/views/users/edit.html.erb +6 -0
- data/spec/dummy/app/views/users/index.html.erb +25 -0
- data/spec/dummy/app/views/users/new.html.erb +5 -0
- data/spec/dummy/app/views/users/show.html.erb +4 -0
- data/spec/dummy/app/views/versions/_form.html.erb +17 -0
- data/spec/dummy/app/views/versions/edit.html.erb +6 -0
- data/spec/dummy/app/views/versions/index.html.erb +25 -0
- data/spec/dummy/app/views/versions/new.html.erb +5 -0
- data/spec/dummy/app/views/versions/show.html.erb +4 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +9 -0
- data/spec/dummy/bin/rake +9 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/bin/spring +16 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +26 -0
- data/spec/dummy/config/boot.rb +3 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +76 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20110803201325_create_test_bed.rb +98 -0
- data/spec/dummy/db/migrate/20121009161700_add_digitals.rb +24 -0
- data/spec/dummy/db/migrate/20161005123106_create_digitals.rb +8 -0
- data/spec/dummy/db/migrate/20161005123106_create_long_and_complex_table_linked_to_versions.rb +8 -0
- data/spec/dummy/db/migrate/20161005123107_create_loader_releases.rb +8 -0
- data/spec/dummy/db/migrate/20161005123108_create_owners.rb +8 -0
- data/spec/dummy/db/migrate/20161005123109_create_empties.rb +8 -0
- data/spec/dummy/db/migrate/20161005123110_create_projects.rb +8 -0
- data/spec/dummy/db/migrate/20161005123111_create_users.rb +8 -0
- data/spec/dummy/db/migrate/20161005123111_create_versions.rb +8 -0
- data/spec/dummy/db/migrate/20161005123112_create_milestones.rb +8 -0
- data/spec/dummy/db/migrate/20161005123113_create_categories.rb +8 -0
- data/spec/dummy/db/schema.rb +93 -0
- data/spec/dummy/db/seeds.rb +9 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +69 -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/dummy/public/robots.txt +5 -0
- data/spec/dummy/sandbox_example.thor +4 -0
- data/spec/dummy/test/controllers/categories_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/digitals_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/empties_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/loader_releases_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/long_and_complex_table_linked_to_versions_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/milestones_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/owners_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/projects_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/users_controller_test.rb +49 -0
- data/spec/dummy/test/controllers/versions_controller_test.rb +49 -0
- data/spec/dummy/test/factories/categories.rb +5 -0
- data/spec/dummy/test/factories/digitals.rb +5 -0
- data/spec/dummy/test/factories/empties.rb +5 -0
- data/spec/dummy/test/factories/loader_releases.rb +5 -0
- data/spec/dummy/test/factories/long_and_complex_table_linked_to_versions.rb +5 -0
- data/spec/dummy/test/factories/milestones.rb +5 -0
- data/spec/dummy/test/factories/owners.rb +5 -0
- data/spec/dummy/test/factories/projects.rb +5 -0
- data/spec/dummy/test/factories/users.rb +5 -0
- data/spec/dummy/test/factories/versions.rb +5 -0
- data/spec/dummy/test/models/category_test.rb +7 -0
- data/spec/dummy/test/models/digital_test.rb +7 -0
- data/spec/dummy/test/models/empty_test.rb +7 -0
- data/spec/dummy/test/models/loader_release_test.rb +7 -0
- data/spec/dummy/test/models/long_and_complex_table_linked_to_version_test.rb +7 -0
- data/spec/dummy/test/models/milestone_test.rb +7 -0
- data/spec/dummy/test/models/owner_test.rb +7 -0
- data/spec/dummy/test/models/project_test.rb +7 -0
- data/spec/dummy/test/models/user_test.rb +7 -0
- data/spec/dummy/test/models/version_test.rb +7 -0
- data/spec/dummy/test/test_helper.rb +10 -0
- data/spec/exporters/csv_exporter_spec.rb +240 -0
- data/spec/exporters/csv_generator_spec.rb +139 -0
- data/spec/exporters/excel_exporter_spec.rb +193 -0
- data/spec/exporters/excel_generator_spec.rb +181 -0
- data/spec/exporters/generator_base_spec.rb +45 -0
- data/spec/factories/categories.rb +7 -0
- data/spec/factories/factories.rb +18 -0
- data/spec/factories/milestone.rb +16 -0
- data/spec/factories/projects.rb +41 -0
- data/spec/fixtures/BadAssociationName.xls +0 -0
- data/spec/fixtures/DemoNegativeTesting.xls +0 -0
- data/spec/fixtures/ProjectConfiguration.yml +18 -0
- data/spec/fixtures/ProjectsMultiCategories.xls +0 -0
- data/spec/fixtures/ProjectsMultiCategoriesHeaderLookup.xls +0 -0
- data/spec/fixtures/ProjectsSingleCategories.xls +0 -0
- data/spec/fixtures/ProjectsSingleCategories.xlsx +0 -0
- data/spec/fixtures/SimpleProjects.xls +0 -0
- data/spec/fixtures/config/database.yml +28 -0
- data/spec/fixtures/csv/BadAssociationName.csv +6 -0
- data/spec/fixtures/csv/DemoNegativeTesting.csv +6 -0
- data/spec/fixtures/csv/ProjectsMultiCategories.csv +5 -0
- data/spec/fixtures/csv/ProjectsMultiCategoriesHeaderLookup.csv +5 -0
- data/spec/fixtures/csv/ProjectsSingleCategories.csv +5 -0
- data/spec/fixtures/csv/SimpleProjects.csv +4 -0
- data/spec/fixtures/db/migrate/20110803201325_create_test_bed.rb +98 -0
- data/spec/fixtures/db/migrate/20121009161700_add_digitals.rb +24 -0
- data/spec/fixtures/db/seeds.rb +9 -0
- data/spec/fixtures/images/DEMO_001_ror_bag.jpeg +0 -0
- data/spec/fixtures/images/DEMO_002_Powerstation.jpeg +0 -0
- data/spec/fixtures/images/DEMO_003_ror_mug.jpeg +0 -0
- data/spec/fixtures/images/DEMO_004_ror_ringer.jpeg +0 -0
- data/spec/fixtures/load_datashift.thor +3 -0
- data/spec/fixtures/models/category.rb +6 -0
- data/spec/fixtures/models/digital.rb +22 -0
- data/spec/fixtures/models/empty.rb +2 -0
- data/spec/fixtures/models/loader_release.rb +10 -0
- data/spec/fixtures/models/long_and_complex_table_linked_to_version.rb +6 -0
- data/spec/fixtures/models/milestone.rb +15 -0
- data/spec/fixtures/models/owner.rb +13 -0
- data/spec/fixtures/models/project.rb +53 -0
- data/spec/fixtures/models/user.rb +5 -0
- data/spec/fixtures/models/version.rb +7 -0
- data/spec/fixtures/results/exp_project_assoc_headers.xls +0 -0
- data/spec/fixtures/results/exp_project_collection_spec.csv +2 -0
- data/spec/fixtures/results/exp_project_export.xls +0 -0
- data/spec/fixtures/results/exp_project_first_export.xls +0 -0
- data/spec/fixtures/results/exp_project_plus_assoc.xls +0 -0
- data/spec/fixtures/results/exp_project_plus_assoc_export_spec.csv +9 -0
- data/spec/fixtures/results/gen_project_plus_assoc_template.xls +0 -0
- data/spec/fixtures/results/gen_project_plus_some_assoc_template.xls +0 -0
- data/spec/fixtures/results/gen_project_template.xls +0 -0
- data/spec/fixtures/results/project_and_assoc_in_hash_export.xls +0 -0
- data/spec/fixtures/results/project_and_assoc_in_json_export.csv +9 -0
- data/spec/fixtures/results/project_and_assoc_in_json_export.xls +0 -0
- data/spec/fixtures/results/project_export_spec_with_custom_delim_,.csv +2 -0
- data/spec/fixtures/results/project_export_spec_with_custom_delim_/302/243.csv +2 -0
- data/spec/fixtures/results/project_export_spec_with_custom_delim_/302/247.csv +2 -0
- data/spec/fixtures/results/project_plus_assoc_template.csv +1 -0
- data/spec/fixtures/results/project_plus_some_assoc_template.csv +1 -0
- data/spec/fixtures/results/project_remove_export_spec.csv +2 -0
- data/spec/fixtures/results/project_template.csv +1 -0
- data/spec/fixtures/results/project_with_methods_export_spec.csv +2 -0
- data/spec/fixtures/results/thor_spec_gen_project.csv +1 -0
- data/spec/fixtures/sandbox_example.thor +4 -0
- data/spec/fixtures/simple_export_spec.xls +0 -0
- data/spec/fixtures/simple_template_spec.xls +0 -0
- data/spec/fixtures/test_model_defs.rb +7 -0
- data/spec/loaders/csv_loader_spec.rb +206 -0
- data/spec/loaders/data_flow_excel_loader_spec.rb +290 -0
- data/spec/loaders/excel_loader_failures_spec.rb +67 -0
- data/spec/loaders/excel_loader_spec.rb +294 -0
- data/spec/loaders/loader_base_spec.rb +29 -0
- data/spec/loaders/paperclip_loader_spec.rb +106 -0
- data/spec/log/datashift.log +14930 -0
- data/spec/private/digitals/1/DEMO_003_ror_mug.jpeg +0 -0
- data/spec/private/digitals/2/DEMO_002_Powerstation.jpeg +0 -0
- data/spec/private/digitals/3/DEMO_004_ror_ringer.jpeg +0 -0
- data/spec/private/digitals/4/DEMO_001_ror_bag.jpeg +0 -0
- data/spec/spec_helper.rb +26 -230
- data/spec/support/clear_and_manage_contexts.rb +25 -0
- data/spec/support/database_cleaner.rb +32 -0
- data/spec/support/datashift_test_helpers.rb +153 -0
- data/spec/support/files_paths_helper.rb +13 -0
- data/spec/support/fixtures/results/mapping_template.yaml +15 -0
- data/spec/support/sandbox.rb +136 -0
- metadata +804 -85
- data/README.markdown +0 -274
- data/README.rdoc +0 -19
- data/VERSION +0 -1
- data/datashift.gemspec +0 -48
- data/lib/applications/jruby/old_pre_proxy_jexcel_file.rb +0 -437
- data/lib/datashift/data_transforms.rb +0 -83
- data/lib/datashift/mapping_file_definitions.rb +0 -88
- data/lib/datashift/mapping_service.rb +0 -91
- data/lib/datashift/method_detail.rb +0 -165
- data/lib/datashift/method_details_manager.rb +0 -95
- data/lib/datashift/method_dictionary.rb +0 -281
- data/lib/datashift/method_mapper.rb +0 -174
- data/lib/datashift/thor_base.rb +0 -38
- data/lib/generators/mapping_generator.rb +0 -112
- data/lib/helpers/core_ext/csv_file.rb +0 -33
- data/lib/helpers/core_ext/to_b.rb +0 -24
- data/lib/loaders/reporter.rb +0 -58
- data/lib/thor/export.thor +0 -175
- data/lib/thor/generate.thor +0 -191
- data/lib/thor/import.thor +0 -110
- data/lib/thor/mapping.thor +0 -65
- data/lib/thor/tools.thor +0 -84
- data/spec/Gemfile +0 -31
- data/spec/Gemfile.lock +0 -134
- data/spec/csv_exporter_spec.rb +0 -144
- data/spec/csv_generator_spec.rb +0 -159
- data/spec/csv_loader_spec.rb +0 -212
- data/spec/datashift_spec.rb +0 -55
- data/spec/excel_exporter_spec.rb +0 -199
- data/spec/excel_generator_spec.rb +0 -203
- data/spec/excel_loader_spec.rb +0 -237
- data/spec/excel_spec.rb +0 -203
- data/spec/loader_base_spec.rb +0 -166
- data/spec/mapping_spec.rb +0 -117
- data/spec/method_dictionary_spec.rb +0 -300
- data/spec/method_mapper_spec.rb +0 -100
- data/spec/model_mapper_spec.rb +0 -41
- data/spec/paperclip_loader_spec.rb +0 -92
- data/spec/populator_spec.rb +0 -128
- data/spec/thor_spec.rb +0 -90
- data/tasks/file_tasks.rake +0 -37
- data/tasks/word_to_seedfu.rake +0 -167
|
@@ -1,92 +1,37 @@
|
|
|
1
|
-
# Copyright:: (c) Autotelik Media Ltd
|
|
1
|
+
# Copyright:: (c) Autotelik Media Ltd 2015
|
|
2
2
|
# Author :: Tom Statter
|
|
3
|
-
# Date :: Aug 2010
|
|
4
3
|
# License:: MIT
|
|
5
4
|
#
|
|
6
|
-
#
|
|
5
|
+
# Details:: Base class for generators, which provide services to describe a Model in an external format
|
|
7
6
|
#
|
|
8
7
|
module DataShift
|
|
9
8
|
|
|
10
9
|
class GeneratorBase
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
include DataShift::Logging
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
@filename = filename
|
|
16
|
-
@headers = []
|
|
17
|
-
@remove_list =[]
|
|
18
|
-
end
|
|
13
|
+
attr_accessor :configuration
|
|
19
14
|
|
|
20
|
-
def
|
|
21
|
-
@rails_standard_columns ||= [:id, :created_at, :created_on, :updated_at, :updated_on]
|
|
15
|
+
def initialize
|
|
22
16
|
end
|
|
23
17
|
|
|
24
|
-
|
|
25
|
-
#
|
|
26
|
-
# based on association requirements,
|
|
27
|
-
#
|
|
28
|
-
# Default is to include *everything*
|
|
29
|
-
#
|
|
30
|
-
# * <tt>:exclude</tt> - Association TYPE(s) to exclude completely.
|
|
31
|
-
#
|
|
32
|
-
# Possible association_type values are given by MethodDetail::supported_types_enum
|
|
33
|
-
# ... [:assignment, :belongs_to, :has_one, :has_many]
|
|
18
|
+
# Prepare to generate with associations but then
|
|
19
|
+
# calls a **derived generate** method i.e abstract to this base class
|
|
34
20
|
#
|
|
35
|
-
#
|
|
21
|
+
# file_name => Filename for generated template
|
|
36
22
|
#
|
|
37
|
-
|
|
38
|
-
#
|
|
39
|
-
# * <tt>:include_rails</tt> - Specify to keep Rails columns in mappings
|
|
40
|
-
#
|
|
41
|
-
def prepare_model_headers(method_details_mgr, options = {})
|
|
42
|
-
|
|
43
|
-
work_list = MethodDetail::supported_types_enum.to_a - [ *options[:exclude] ]
|
|
44
|
-
|
|
45
|
-
@headers = []
|
|
46
|
-
|
|
47
|
-
work_list.each do |assoc_type|
|
|
48
|
-
method_details_for_assoc_type = method_details_mgr.get_list_of_method_details(assoc_type)
|
|
49
|
-
|
|
50
|
-
next if(method_details_for_assoc_type.nil? || method_details_for_assoc_type.empty?)
|
|
51
|
-
|
|
52
|
-
method_details_for_assoc_type.each do |md|
|
|
53
|
-
#comparable_association = md.operator.to_s.downcase.to_sym
|
|
54
|
-
#i = remove_list.index { |r| r == comparable_association }
|
|
55
|
-
#(i) ? remove_list.delete_at(i) : @headers << "#{md.operator}"
|
|
56
|
-
@headers << md.operator
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
remove_headers(options)
|
|
61
|
-
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# Parse options and remove headers
|
|
65
|
-
# Specify columns to remove with :
|
|
66
|
-
# options[:remove]
|
|
67
|
-
# Rails columns like id, created_at are removed by default,
|
|
68
|
-
# to keep them in specify
|
|
69
|
-
# options[:include_rails]
|
|
70
|
-
#
|
|
71
|
-
def remove_headers(options)
|
|
72
|
-
remove_list = prep_remove_list( options )
|
|
73
|
-
|
|
74
|
-
#TODO - more efficient way ?
|
|
75
|
-
headers.delete_if { |h| remove_list.include?( h.to_sym ) } unless(remove_list.empty?)
|
|
76
|
-
end
|
|
23
|
+
def generate_with_associations(file_name, klass)
|
|
77
24
|
|
|
25
|
+
state = DataShift::Configuration.call.with
|
|
78
26
|
|
|
79
|
-
|
|
80
|
-
# Rails columns like id, created_at etc are added to the remove list by default
|
|
81
|
-
# Specify :include_rails to keep them in
|
|
82
|
-
def prep_remove_list( options )
|
|
83
|
-
remove_list = [ *options[:remove] ].compact.collect{|x| x.to_s.downcase.to_sym }
|
|
27
|
+
DataShift::Configuration.call.with = :all
|
|
84
28
|
|
|
85
|
-
|
|
29
|
+
generate(file_name, klass)
|
|
30
|
+
ensure
|
|
31
|
+
DataShift::Configuration.call.with = state
|
|
86
32
|
|
|
87
|
-
remove_list
|
|
88
33
|
end
|
|
89
34
|
|
|
90
35
|
end
|
|
91
36
|
|
|
92
|
-
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Copyright:: (c) Autotelik Media Ltd 2015
|
|
2
|
+
# Author :: Tom Statter
|
|
3
|
+
# Date :: Feb 2015
|
|
4
|
+
# License:: MIT
|
|
5
|
+
#
|
|
6
|
+
# Details:: Read mappings and provide cache type services for source=>destination mappings
|
|
7
|
+
#
|
|
8
|
+
require 'erubis'
|
|
9
|
+
|
|
10
|
+
module DataShift
|
|
11
|
+
|
|
12
|
+
module Loaders
|
|
13
|
+
|
|
14
|
+
class Configuration < DataShift::Configuration
|
|
15
|
+
|
|
16
|
+
# Default is to stop processing once we hit a completely empty row. Over ride.
|
|
17
|
+
# WARNING maybe slow, as will process all rows as defined by Excel
|
|
18
|
+
# @param [Boolean]
|
|
19
|
+
#
|
|
20
|
+
attr_accessor :allow_empty_rows
|
|
21
|
+
|
|
22
|
+
# Destroy failed objects - if object.save fails at any point destroy the current object - all or nothing
|
|
23
|
+
# Default is true - database is cleaned up
|
|
24
|
+
# @param [Boolean]
|
|
25
|
+
#
|
|
26
|
+
attr_accessor :destroy_on_failure
|
|
27
|
+
|
|
28
|
+
# Stop processing and abort if any row fails to import
|
|
29
|
+
# Default is false - row reported as failure but loading continues
|
|
30
|
+
# @param [Boolean]
|
|
31
|
+
#
|
|
32
|
+
attr_accessor :abort_on_failure
|
|
33
|
+
|
|
34
|
+
# Row containing headers - default is 0
|
|
35
|
+
# @param [Integer]
|
|
36
|
+
#
|
|
37
|
+
attr_writer :header_row
|
|
38
|
+
|
|
39
|
+
def initialize
|
|
40
|
+
@mandatory = []
|
|
41
|
+
@allow_empty_rows = false
|
|
42
|
+
@abort_on_failure = false
|
|
43
|
+
@destroy_on_failure = true
|
|
44
|
+
@header_row = 0
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Custom Readers
|
|
48
|
+
|
|
49
|
+
def header_row
|
|
50
|
+
raise MissingHeadersError, "Minimum row for Headers is 0 - passed #{@header_row}" if @header_row.to_i < 0
|
|
51
|
+
@header_row
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [DataShift::Loaders::Configuration] DataShift's current configuration
|
|
55
|
+
def self.call
|
|
56
|
+
@configuration ||= Loaders::Configuration.new
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.reset
|
|
60
|
+
@configuration = Loaders::Configuration.new
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Set DataShift's configure
|
|
64
|
+
# @param config [DataShift::Loaders::Configuration]
|
|
65
|
+
class << self
|
|
66
|
+
attr_writer :configuration
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Modify DataShift's current Import configuration
|
|
70
|
+
# ```
|
|
71
|
+
# DataShift::Loaders::Configuration.configure do |config|
|
|
72
|
+
# config.verbose = false
|
|
73
|
+
# end
|
|
74
|
+
# ```
|
|
75
|
+
def self.configure
|
|
76
|
+
yield call
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Modify DataShift's current Import configuration from an options hash
|
|
80
|
+
|
|
81
|
+
def self.from_hash( options )
|
|
82
|
+
DataShift::Loaders::Configuration.configure do |config|
|
|
83
|
+
config.mandatory = options[:mandatory] if(options[:mandatory])
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
data/lib/loaders/csv_loader.rb
CHANGED
|
@@ -4,144 +4,106 @@
|
|
|
4
4
|
# License:: MIT
|
|
5
5
|
#
|
|
6
6
|
# Details:: Specific loader to support CSV files.
|
|
7
|
-
#
|
|
8
7
|
#
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
require 'datashift/method_mapper'
|
|
8
|
+
#
|
|
9
|
+
require_relative 'file_loader'
|
|
12
10
|
|
|
13
11
|
module DataShift
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
class CsvLoader < LoaderBase
|
|
16
14
|
|
|
17
15
|
include DataShift::Logging
|
|
16
|
+
include DataShift::FileLoader
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
super
|
|
20
|
+
end
|
|
18
21
|
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# [:dummy] : Perform a dummy run - attempt to load everything but then roll back
|
|
22
|
+
# Options
|
|
23
|
+
#
|
|
24
|
+
# [:allow_empty_rows] : Default is to stop processing once we hit a completely empty row. Over ride.
|
|
25
|
+
# WARNING maybe slow, as will process all rows as defined by Excel
|
|
26
|
+
#
|
|
27
|
+
# [:dummy] : Perform a dummy run - attempt to load everything but then roll back
|
|
28
|
+
#
|
|
27
29
|
#
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# [:mandatory] : Array of mandatory column names
|
|
31
|
-
# [:force_inclusion] : Array of inbound column names to force into mapping
|
|
32
|
-
# [:include_all] : Include all headers in processing - takes precedence of :force_inclusion
|
|
33
|
-
# [:strict] : Raise exception when no mapping found for a column heading (non mandatory)
|
|
30
|
+
def perform_load( _options = {} )
|
|
31
|
+
require 'csv'
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
raise "Cannot load - failed to create a #{klass}" unless load_object
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
logger.info "Starting bulk load from CSV : #{file_name}"
|
|
38
36
|
|
|
39
|
-
# TODO - can we abstract out what a 'parsed file' is -
|
|
37
|
+
# TODO: - can we abstract out what a 'parsed file' is - headers plus value of each node
|
|
38
|
+
# so a common object can represent excel,csv etc
|
|
40
39
|
# then we can make load() more generic
|
|
41
40
|
|
|
42
|
-
|
|
41
|
+
parsed_file = CSV.read(file_name)
|
|
43
42
|
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
# assume headers are row 0
|
|
44
|
+
header_idx = 0
|
|
45
|
+
header_row = parsed_file.shift
|
|
46
|
+
|
|
47
|
+
set_headers( DataShift::Headers.new(:csv, header_idx, header_row) )
|
|
48
|
+
|
|
49
|
+
# maps list of headers into suitable calls on the Active Record class
|
|
50
|
+
bind_headers(headers)
|
|
47
51
|
|
|
48
|
-
puts "\n\n\nLoading from CSV file: #{file_name}"
|
|
49
|
-
puts "Processing #{@parsed_file.size} rows"
|
|
50
52
|
begin
|
|
53
|
+
puts 'Dummy Run - Changes will be rolled back' if(configuration.dummy_run)
|
|
51
54
|
|
|
52
55
|
load_object_class.transaction do
|
|
53
|
-
|
|
56
|
+
logger.info "Processing #{parsed_file.size} rows"
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
parsed_file.each_with_index do |row, i|
|
|
59
|
+
current_row_idx = i
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
logger.info "Processing Row #{i} : #{row}"
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
# Iterate over the bindings, creating a context from data in associated Excel column
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
@binder.bindings.each_with_index do |method_binding, i|
|
|
66
|
+
unless method_binding.valid?
|
|
67
|
+
logger.warn("No binding was found for column (#{i})")
|
|
68
|
+
next
|
|
69
|
+
end
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
# Does not currently ensure mandatory columns (for valid?) processed first but model needs saving
|
|
69
|
-
# before associations can be processed so user should ensure mandatory columns are prior to associations
|
|
71
|
+
value = row[method_binding.inbound_index] # binding contains column number
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
# has_and_belongs_to associations which require the load_object has an id for the join table
|
|
73
|
+
context = doc_context.create_node_context(method_binding, i, value)
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
# pulling data out of associated column
|
|
76
|
-
@method_mapper.method_details.each_with_index do |method_detail, col|
|
|
75
|
+
logger.info "Processing Column #{method_binding.inbound_index} (#{method_binding.pp})"
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
begin
|
|
78
|
+
context.process
|
|
79
|
+
rescue => x
|
|
80
|
+
if doc_context.all_or_nothing?
|
|
81
|
+
logger.error('All or nothing set and Current Columnfailed so complete Row aborted')
|
|
82
|
+
break
|
|
81
83
|
end
|
|
82
|
-
|
|
83
|
-
value = row[col]
|
|
84
|
-
|
|
85
|
-
process(method_detail, value)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
rescue => e
|
|
89
|
-
failure(row, true)
|
|
90
|
-
logger.error e.inspect
|
|
91
|
-
logger.error e.backtrace.first.inspect
|
|
92
|
-
logger.error "Failed to process row [#{@reporter.processed_object_count}] (#{@current_row})"
|
|
93
|
-
|
|
94
|
-
if(verbose)
|
|
95
|
-
puts "Failed to process row [#{@reporter.processed_object_count}] (#{@current_row})"
|
|
96
|
-
puts e.inspect
|
|
97
84
|
end
|
|
85
|
+
end # end of each column(node)
|
|
98
86
|
|
|
99
|
-
|
|
100
|
-
new_load_object
|
|
101
|
-
next
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# TODO - make optional - all or nothing or carry on and dump out the exception list at end
|
|
105
|
-
|
|
106
|
-
logger.debug "Attempting Save on : #{load_object.inspect}"
|
|
87
|
+
doc_context.save_and_monitor_progress
|
|
107
88
|
|
|
108
|
-
|
|
89
|
+
doc_context.reset unless doc_context.node_context.next_update?
|
|
90
|
+
end # all rows processed
|
|
109
91
|
|
|
110
|
-
|
|
111
|
-
|
|
92
|
+
if(configuration.dummy_run)
|
|
93
|
+
puts 'CSV loading stage done - Dummy run so Rolling Back.'
|
|
94
|
+
raise ActiveRecord::Rollback # Don't actually create/upload to DB if we are doing dummy run
|
|
112
95
|
end
|
|
96
|
+
end # TRANSACTION N.B ActiveRecord::Rollback does not propagate outside of the containing transaction block
|
|
113
97
|
|
|
114
|
-
raise ActiveRecord::Rollback if(options[:dummy]) # Don't actually create/upload to DB if we are doing dummy run
|
|
115
|
-
end
|
|
116
98
|
rescue => e
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
logger.info "CSV loading stage complete - Dummy run so Rolling Back."
|
|
120
|
-
else
|
|
121
|
-
raise e
|
|
122
|
-
end
|
|
99
|
+
puts "ERROR: CSV loading failed : #{e.inspect}"
|
|
100
|
+
raise e
|
|
123
101
|
ensure
|
|
124
102
|
report
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
end
|
|
128
|
-
end
|
|
103
|
+
end
|
|
129
104
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
include DataShift::CsvLoading
|
|
133
|
-
|
|
134
|
-
def initialize(klass, object = nil, options = {})
|
|
135
|
-
super( klass, object, options )
|
|
136
|
-
raise "Cannot load - failed to create a #{klass}" unless @load_object
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def perform_load( file_name, options = {} )
|
|
140
|
-
perform_csv_load( file_name, options )
|
|
141
|
-
|
|
142
|
-
puts "CSV loading stage complete - #{loaded_count} rows added."
|
|
105
|
+
puts 'CSV loading stage Complete.'
|
|
143
106
|
end
|
|
144
107
|
|
|
145
108
|
end
|
|
146
|
-
|
|
147
|
-
end
|
|
109
|
+
end
|
data/lib/loaders/excel_loader.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
# Copyright:: (c) Autotelik Media Ltd
|
|
1
|
+
# Copyright:: (c) Autotelik Media Ltd 2015
|
|
2
2
|
# Author :: Tom Statter
|
|
3
|
-
# Date :: Aug 2011
|
|
4
3
|
# License:: MIT
|
|
5
4
|
#
|
|
6
5
|
# Details:: Specific loader to support Excel files.
|
|
@@ -10,127 +9,100 @@
|
|
|
10
9
|
# Iterates over all the rows using mapped operations to assign row data to a database object,
|
|
11
10
|
# i.e pulls data from each column and sends to object.
|
|
12
11
|
#
|
|
13
|
-
|
|
14
|
-
require 'datashift/exceptions'
|
|
12
|
+
require_relative 'file_loader'
|
|
15
13
|
|
|
16
14
|
module DataShift
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
require 'excel'
|
|
21
|
-
|
|
22
|
-
module ExcelLoading
|
|
23
|
-
|
|
24
|
-
include ExcelBase
|
|
25
|
-
|
|
26
|
-
attr_accessor :excel
|
|
27
|
-
|
|
28
|
-
# Currently struggling to determine the 'end' of data in a spreadsheet
|
|
29
|
-
# this reflects if current row had any data at all
|
|
30
|
-
attr_reader :contains_data
|
|
31
|
-
|
|
32
|
-
def start_excel( file_name, options = {} )
|
|
33
|
-
|
|
34
|
-
@excel = Excel.new
|
|
35
|
-
|
|
36
|
-
excel.open(file_name)
|
|
37
|
-
|
|
38
|
-
puts "\n\n\nLoading from Excel file: #{file_name}"
|
|
39
|
-
logger.info("\nStarting Load from Excel file: #{file_name}")
|
|
40
|
-
|
|
41
|
-
sheet_number = options[:sheet_number] || 0
|
|
42
|
-
|
|
43
|
-
@sheet = excel.worksheet( sheet_number )
|
|
44
|
-
|
|
45
|
-
parse_headers(@sheet, options[:header_row])
|
|
46
|
-
|
|
47
|
-
raise MissingHeadersError, "No headers found - Check Sheet #{@sheet} is complete and Row #{header_row_index} contains headers" if(excel_headers.empty?)
|
|
16
|
+
class ExcelLoader < LoaderBase
|
|
48
17
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
populate_method_mapper_from_headers(excel_headers, options )
|
|
18
|
+
include DataShift::ExcelBase
|
|
19
|
+
include DataShift::FileLoader
|
|
52
20
|
|
|
53
|
-
|
|
21
|
+
def initialize
|
|
22
|
+
super
|
|
54
23
|
end
|
|
55
24
|
|
|
56
|
-
# Options
|
|
57
|
-
#
|
|
58
|
-
#
|
|
25
|
+
# Options
|
|
26
|
+
#
|
|
27
|
+
# [:sheet_name] : Create a new worksheet assign to @sheet. Default is class.name
|
|
59
28
|
# [:sheet_number] : Default is 0. The index of the Excel Worksheet to use.
|
|
60
|
-
#
|
|
61
|
-
|
|
62
|
-
# Options passed through to : populate_method_mapper_from_headers
|
|
63
|
-
#
|
|
64
|
-
# [:mandatory] : Array of mandatory column names
|
|
65
|
-
# [:force_inclusion] : Array of inbound column names to force into mapping
|
|
66
|
-
# [:include_all] : Include all headers in processing - takes precedence of :force_inclusion
|
|
67
|
-
# [:strict] : Raise exception when no mapping found for a column heading (non mandatory)
|
|
29
|
+
#
|
|
30
|
+
def perform_load( options = {} )
|
|
68
31
|
|
|
69
|
-
|
|
32
|
+
allow_empty_rows = DataShift::Loaders::Configuration.call.allow_empty_rows
|
|
33
|
+
|
|
34
|
+
logger.info "Starting bulk load from Excel : #{file_name}"
|
|
70
35
|
|
|
71
|
-
|
|
36
|
+
start(file_name, options)
|
|
72
37
|
|
|
73
|
-
|
|
38
|
+
# maps list of headers into suitable calls on the Active Record class
|
|
39
|
+
bind_headers(headers)
|
|
74
40
|
|
|
75
41
|
begin
|
|
76
|
-
puts
|
|
42
|
+
puts 'Dummy Run - Changes will be rolled back' if(configuration.dummy_run)
|
|
77
43
|
|
|
78
44
|
load_object_class.transaction do
|
|
79
|
-
|
|
80
|
-
@sheet.each_with_index do |row, i|
|
|
81
|
-
|
|
45
|
+
sheet.each_with_index do |row, i|
|
|
82
46
|
current_row_idx = i
|
|
83
|
-
@current_row = row
|
|
84
47
|
|
|
85
|
-
next if
|
|
48
|
+
next if current_row_idx == headers.idx
|
|
86
49
|
|
|
87
50
|
# Excel num_rows seems to return all 'visible' rows, which appears to be greater than the actual data rows
|
|
88
51
|
# (TODO - write spec to process .xls with a huge number of rows)
|
|
89
52
|
#
|
|
90
|
-
#
|
|
53
|
+
# manually have to detect when actual data ends, this isn't very smart but
|
|
91
54
|
# got no better idea than ending once we hit the first completely empty row
|
|
92
|
-
break if(
|
|
55
|
+
break if !allow_empty_rows && (row.nil? || row.empty?)
|
|
93
56
|
|
|
94
|
-
logger.info "Processing Row #{current_row_idx}
|
|
57
|
+
logger.info "Processing Row #{current_row_idx}"
|
|
95
58
|
|
|
96
|
-
|
|
59
|
+
contains_data = false
|
|
97
60
|
|
|
98
|
-
|
|
61
|
+
doc_context.progress_monitor.start_monitoring
|
|
99
62
|
|
|
100
|
-
|
|
63
|
+
# Iterate over the bindings,
|
|
64
|
+
# For each column bound to a model operator, create a context from data in associated Excel column
|
|
101
65
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
66
|
+
@binder.bindings.each_with_index do |method_binding, _i|
|
|
67
|
+
unless method_binding.valid?
|
|
68
|
+
logger.warn("No binding was found for column (#{current_row_idx})")
|
|
69
|
+
next
|
|
70
|
+
end
|
|
105
71
|
|
|
106
|
-
|
|
107
|
-
|
|
72
|
+
# get the value from the cell, binding contains the column number
|
|
73
|
+
value = row[method_binding.inbound_index]
|
|
108
74
|
|
|
109
|
-
|
|
110
|
-
new_load_object
|
|
111
|
-
next
|
|
112
|
-
end
|
|
75
|
+
context = doc_context.create_node_context(method_binding, current_row_idx, value)
|
|
113
76
|
|
|
114
|
-
|
|
77
|
+
contains_data ||= context.contains_data?
|
|
115
78
|
|
|
116
|
-
|
|
117
|
-
@reporter.processed_object_count += 1
|
|
79
|
+
logger.info "Processing Column #{method_binding.inbound_index} (#{method_binding.pp})"
|
|
118
80
|
|
|
119
|
-
|
|
81
|
+
begin
|
|
82
|
+
context.process
|
|
83
|
+
rescue
|
|
84
|
+
if doc_context.all_or_nothing?
|
|
85
|
+
logger.error('All or nothing set and Current Column failed so complete Row aborted')
|
|
86
|
+
break
|
|
87
|
+
end
|
|
88
|
+
end
|
|
120
89
|
|
|
121
|
-
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Excel data rows not accurate, seems to have to manually detect when actual Excel data rows end
|
|
93
|
+
break if !allow_empty_rows && contains_data == false
|
|
122
94
|
|
|
123
|
-
|
|
124
|
-
new_load_object
|
|
95
|
+
doc_context.save_and_monitor_progress
|
|
125
96
|
|
|
126
|
-
|
|
97
|
+
# unless next operation is update, reset the loader object
|
|
98
|
+
doc_context.reset unless doc_context.node_context.next_update?
|
|
99
|
+
end # all rows processed
|
|
127
100
|
|
|
128
|
-
if(
|
|
129
|
-
puts
|
|
101
|
+
if(configuration.dummy_run)
|
|
102
|
+
puts 'Excel loading stage done - Dummy run so Rolling Back.'
|
|
130
103
|
raise ActiveRecord::Rollback # Don't actually create/upload to DB if we are doing dummy run
|
|
131
104
|
end
|
|
132
|
-
|
|
133
|
-
end # TRANSACTION N.B ActiveRecord::Rollback does not propagate outside of the containing transaction block
|
|
105
|
+
end # TRANSACTION N.B ActiveRecord::Rollback does not propagate outside of the containing transaction block
|
|
134
106
|
|
|
135
107
|
rescue => e
|
|
136
108
|
puts "ERROR: Excel loading failed : #{e.inspect}"
|
|
@@ -139,86 +111,29 @@ module DataShift
|
|
|
139
111
|
report
|
|
140
112
|
end
|
|
141
113
|
|
|
114
|
+
puts 'Excel loading stage Complete.'
|
|
142
115
|
end
|
|
143
116
|
|
|
144
|
-
|
|
145
|
-
failure(@current_row, delete_object)
|
|
146
|
-
|
|
147
|
-
if(verbose)
|
|
148
|
-
puts "perform_excel_load failed in row [#{current_row_idx}] #{@current_row} - #{e.message} :"
|
|
149
|
-
puts e.backtrace
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
logger.error "perform_excel_load failed in row [#{current_row_idx}] #{@current_row} - #{e.message} :"
|
|
153
|
-
logger.error e.backtrace.join("\n")
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def value_at(row, column)
|
|
158
|
-
@excel[row, column]
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def process_excel_row(row)
|
|
162
|
-
|
|
163
|
-
# First assign any default values for columns
|
|
164
|
-
process_defaults
|
|
165
|
-
|
|
166
|
-
# TODO - Smart sorting of column processing order ....
|
|
167
|
-
# Does not currently ensure mandatory columns (for valid?) processed first but model needs saving
|
|
168
|
-
# before associations can be processed so user should ensure mandatory columns are prior to associations
|
|
169
|
-
|
|
170
|
-
# as part of this we also attempt to save early, for example before assigning to
|
|
171
|
-
# has_and_belongs_to associations which require the load_object has an id for the join table
|
|
172
|
-
|
|
173
|
-
# Iterate over method_details, working on data out of associated Excel column
|
|
174
|
-
@method_mapper.method_details.each_with_index do |method_detail, i|
|
|
175
|
-
|
|
176
|
-
unless method_detail
|
|
177
|
-
logger.warn("No method_detail found for column (#{i})")
|
|
178
|
-
next # TODO populate unmapped with a real MethodDetail that is 'null' and create is_nil
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
logger.info "Processing Column #{method_detail.column_index} (#{method_detail.operator})"
|
|
182
|
-
|
|
183
|
-
value = row[method_detail.column_index]
|
|
184
|
-
|
|
185
|
-
@contains_data = true unless(value.nil? || value.to_s.empty?)
|
|
186
|
-
|
|
187
|
-
process(method_detail, value)
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
class ExcelLoader < LoaderBase
|
|
196
|
-
|
|
197
|
-
include ExcelLoading
|
|
117
|
+
private
|
|
198
118
|
|
|
199
|
-
#
|
|
200
|
-
#
|
|
201
|
-
# Options to drive building the method dictionary for a class, enabling headers to be mapped to operators on that class.
|
|
119
|
+
# Options :
|
|
202
120
|
#
|
|
203
|
-
#
|
|
204
|
-
#
|
|
205
|
-
# :instance_methods : Include setter/delegate style instance methods for assignment, as well as AR columns
|
|
206
|
-
# :verbose : Verbose logging and to STDOUT
|
|
121
|
+
# [:sheet_name] : Create a new worksheet assign to @sheet. Default is class.name
|
|
122
|
+
# [:sheet_number] : Default is 0. The index of the Excel Worksheet to use.
|
|
207
123
|
#
|
|
208
|
-
def
|
|
209
|
-
|
|
210
|
-
raise "Cannot load - failed to create a #{klass}" unless @load_object
|
|
211
|
-
end
|
|
124
|
+
def start( file_name, options = {} )
|
|
125
|
+
open_excel(file_name, options)
|
|
212
126
|
|
|
127
|
+
header_row = DataShift::Loaders::Configuration.call.header_row
|
|
213
128
|
|
|
214
|
-
|
|
129
|
+
set_headers( parse_headers(sheet, header_row) )
|
|
215
130
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
131
|
+
if headers.empty?
|
|
132
|
+
raise MissingHeadersError, "No headers found - Check Sheet #{sheet} is complete and Row #{headers.idx} contains headers"
|
|
133
|
+
end
|
|
219
134
|
|
|
220
|
-
|
|
135
|
+
excel
|
|
221
136
|
end
|
|
222
137
|
|
|
223
138
|
end
|
|
224
|
-
end
|
|
139
|
+
end
|