zizia 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +65 -0
- data/.rubocop_todo.yml +21 -0
- data/.solr_wrapper +8 -0
- data/.travis.yml +11 -0
- data/Gemfile +12 -0
- data/README.md +77 -0
- data/Rakefile +34 -0
- data/docs/_config.yml +1 -0
- data/docs/index.md +98 -0
- data/lib/zizia/always_invalid_validator.rb +17 -0
- data/lib/zizia/hash_mapper.rb +44 -0
- data/lib/zizia/hyrax_basic_metadata_mapper.rb +149 -0
- data/lib/zizia/hyrax_record_importer.rb +261 -0
- data/lib/zizia/importer.rb +61 -0
- data/lib/zizia/input_record.rb +65 -0
- data/lib/zizia/log_stream.rb +43 -0
- data/lib/zizia/metadata_mapper.rb +83 -0
- data/lib/zizia/metadata_only_stack.rb +70 -0
- data/lib/zizia/parser.rb +132 -0
- data/lib/zizia/parsers/csv_parser.rb +45 -0
- data/lib/zizia/record_importer.rb +57 -0
- data/lib/zizia/spec/fakes/fake_parser.rb +22 -0
- data/lib/zizia/spec/shared_examples/a_mapper.rb +32 -0
- data/lib/zizia/spec/shared_examples/a_message_stream.rb +11 -0
- data/lib/zizia/spec/shared_examples/a_parser.rb +73 -0
- data/lib/zizia/spec/shared_examples/a_validator.rb +46 -0
- data/lib/zizia/spec.rb +15 -0
- data/lib/zizia/streams/formatted_message_stream.rb +70 -0
- data/lib/zizia/validator.rb +117 -0
- data/lib/zizia/validators/csv_format_validator.rb +26 -0
- data/lib/zizia/validators/title_validator.rb +30 -0
- data/lib/zizia/version.rb +5 -0
- data/lib/zizia.rb +73 -0
- data/log/.keep +0 -0
- data/spec/fixtures/bad_example.csv +2 -0
- data/spec/fixtures/example.csv +4 -0
- data/spec/fixtures/hyrax/example.csv +3 -0
- data/spec/fixtures/images/animals/cat.png +0 -0
- data/spec/fixtures/images/zizia.png +0 -0
- data/spec/fixtures/zizia.png +0 -0
- data/spec/integration/import_csv_spec.rb +28 -0
- data/spec/integration/import_hyrax_csv.rb +71 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/stdout_stream_spec.rb +9 -0
- data/spec/support/hyrax/basic_metadata.rb +30 -0
- data/spec/support/hyrax/core_metadata.rb +15 -0
- data/spec/support/shared_contexts/with_work_type.rb +101 -0
- data/spec/zizia/csv_format_validator_spec.rb +38 -0
- data/spec/zizia/csv_parser_spec.rb +73 -0
- data/spec/zizia/formatted_message_stream_spec.rb +35 -0
- data/spec/zizia/hash_mapper_spec.rb +8 -0
- data/spec/zizia/hyrax_basic_metadata_mapper_spec.rb +190 -0
- data/spec/zizia/hyrax_record_importer_spec.rb +178 -0
- data/spec/zizia/importer_spec.rb +46 -0
- data/spec/zizia/input_record_spec.rb +71 -0
- data/spec/zizia/parser_spec.rb +47 -0
- data/spec/zizia/record_importer_spec.rb +70 -0
- data/spec/zizia/title_validator_spec.rb +23 -0
- data/spec/zizia/validator_spec.rb +9 -0
- data/spec/zizia/version_spec.rb +7 -0
- data/spec/zizia_spec.rb +19 -0
- data/zizia.gemspec +34 -0
- metadata +246 -0
data/lib/zizia.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# Bulk object import for Samvera.
|
5
|
+
#
|
6
|
+
# == Importers
|
7
|
+
#
|
8
|
+
# {Importer} is the core class for importing records using {Zizia}.
|
9
|
+
# Importers accept a {Parser} and (optionally) a custom {RecordImporter}, and
|
10
|
+
# process each record in the given parser (see: {Parser#records}).
|
11
|
+
#
|
12
|
+
# @example Importing in bulk from a file
|
13
|
+
# parser = Zizia::Parser.for(file: File.new('path/to/file.ext'))
|
14
|
+
#
|
15
|
+
# Zizia::Importer.new(parser: parser).import if parser.validate
|
16
|
+
#
|
17
|
+
# @example A basic configuration
|
18
|
+
# Zizia.config do |config|
|
19
|
+
# # error/info streams must respond to `#<<`
|
20
|
+
# config.default_error_stream = MyErrorStream.new
|
21
|
+
# config.default_info_stream = STDOUT
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
module Zizia
|
25
|
+
##
|
26
|
+
# @yield the current configuration
|
27
|
+
# @yieldparam config [Zizia::Configuration]
|
28
|
+
#
|
29
|
+
# @return [Zizia::Configuration] the current configuration
|
30
|
+
def config
|
31
|
+
yield @configuration if block_given?
|
32
|
+
@configuration
|
33
|
+
end
|
34
|
+
module_function :config
|
35
|
+
|
36
|
+
require 'zizia/log_stream'
|
37
|
+
##
|
38
|
+
# Module-wide options for `Zizia`.
|
39
|
+
class Configuration
|
40
|
+
##
|
41
|
+
# @!attribute [rw] default_error_stream
|
42
|
+
# @return [#<<]
|
43
|
+
# @!attribute [rw] default_info_stream
|
44
|
+
# @return [#<<]
|
45
|
+
attr_accessor :default_error_stream, :default_info_stream
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
self.default_error_stream = Zizia::LogStream.new
|
49
|
+
self.default_info_stream = Zizia::LogStream.new
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
@configuration = Configuration.new
|
54
|
+
|
55
|
+
require 'zizia/version'
|
56
|
+
require 'zizia/metadata_mapper'
|
57
|
+
require 'zizia/hash_mapper'
|
58
|
+
require 'zizia/hyrax_basic_metadata_mapper'
|
59
|
+
|
60
|
+
require 'zizia/importer'
|
61
|
+
require 'zizia/record_importer'
|
62
|
+
require 'zizia/hyrax_record_importer'
|
63
|
+
|
64
|
+
require 'zizia/input_record'
|
65
|
+
|
66
|
+
require 'zizia/validator'
|
67
|
+
require 'zizia/validators/csv_format_validator'
|
68
|
+
require 'zizia/validators/title_validator'
|
69
|
+
|
70
|
+
require 'zizia/parser'
|
71
|
+
require 'zizia/parsers/csv_parser'
|
72
|
+
require 'zizia/metadata_only_stack'
|
73
|
+
end
|
data/log/.keep
ADDED
File without changes
|
@@ -0,0 +1,4 @@
|
|
1
|
+
title,description
|
2
|
+
Fake Item,A description of a fake item.
|
3
|
+
Fake Item with Quoted Description,"Lorem ipsum dolor sit amet, cu mel habeo antiopam, id pri mucius oporteat. No graeco accumsan deterruisset est. Vix te sonet doctus perpetua, mei at odio eius nostrum. Ex postea quidam menandri duo. Rebum ullum cu mel.\nAperiam malorum indoctum ad nec.\nIn duo nonumes accusata, detraxit adipisci philosophia quo id. Ei usu volutpat vituperatoribus. Ut veniam dolorem qui. Ei legendos erroribus usu. Mentitum moderatius ei est, mei eius magna alterum no. Legere vivendum per ad, vim ei putent facilis."
|
4
|
+
Fake Item with Unicode Description,"Лорем ипсум долор сит амет, ех мовет толлит модератиус ест. Еу яуидам сенсерит цонсецтетуер про, при иисяуе ерудити цоррумпит ат. Ех усу нусяуам пхаедрум темпорибус, ест ат омнесяуе инструцтиор.\nЯуо ех мелиоре инсоленс праесент, иудицо тантас еурипидис хис ут. Аццусам урбанитас инструцтиор ан еам. Но хас вениам дицунт дебитис, нец ут суас аццусам перицула, нец риденс аетерно виртуте не.\nАт про еним вереар, ут солум юсто меи."
|
@@ -0,0 +1,3 @@
|
|
1
|
+
title,depositor,date_modified,label,relative_path,import_url,resource type,creator,contributor,abstract or summary,keyword,license,rights statement,publisher,date created,subject,language,identifier,location,related url,bibliographic_citation,source
|
2
|
+
Work 1 Title,user@example.com,2018-01-01,Work 1 Label,tmp/files,https://example.com,Work 1 Type,Work 1 creator,Work 1 contrib,Desc 1,Key 1,Lic 1,RS 1,Pub 1,2018-06-06,Subj 1,English|~|Japanese,Ident 1,Based 1,https://example.com/related,Bib 1,Source 1
|
3
|
+
Work 2 Title,1970-12-21,,Work 2 Label,,,Work 2 Type,,,Desc 2,,,,Pub 2,,Subj 2
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'importing a csv batch', :clean do
|
6
|
+
subject(:importer) { Zizia::Importer.new(parser: parser) }
|
7
|
+
let(:parser) { Zizia::CsvParser.new(file: file) }
|
8
|
+
let(:file) { File.open('spec/fixtures/example.csv') }
|
9
|
+
|
10
|
+
load File.expand_path("../../support/shared_contexts/with_work_type.rb", __FILE__)
|
11
|
+
include_context 'with a work type'
|
12
|
+
|
13
|
+
it 'creates a record for each CSV line' do
|
14
|
+
expect { importer.import }.to change { Work.count }.to 3
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'validation' do
|
18
|
+
context 'with invalid CSV' do
|
19
|
+
let(:file) { File.open('spec/fixtures/bad_example.csv') }
|
20
|
+
|
21
|
+
it 'outputs invalid file notice to error stream' do
|
22
|
+
expect { parser.validate }
|
23
|
+
.to output(/^CSV::MalformedCSVError.*line 2/)
|
24
|
+
.to_stdout_from_any_process
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe 'importing a CSV with Hyrax defaults', :clean do
|
5
|
+
subject(:importer) { Zizia::Importer.new(parser: parser, record_importer: record_importer) }
|
6
|
+
let(:parser) { Zizia::CsvParser.new(file: csv_file) }
|
7
|
+
let(:record_importer) { Zizia::HyraxRecordImporter.new }
|
8
|
+
|
9
|
+
let(:csv_file) { File.open('spec/fixtures/hyrax/example.csv') }
|
10
|
+
after { csv_file.close }
|
11
|
+
|
12
|
+
load File.expand_path("../../support/shared_contexts/with_work_type.rb", __FILE__)
|
13
|
+
include_context 'with a work type'
|
14
|
+
|
15
|
+
it 'creates the record(s)' do
|
16
|
+
expect { importer.import }.to change { Work.count }.to 2
|
17
|
+
|
18
|
+
works = Work.all
|
19
|
+
work1 = works.find { |w| w.title == ['Work 1 Title'] }
|
20
|
+
work2 = works.find { |w| w.title == ['Work 2 Title'] }
|
21
|
+
|
22
|
+
# First Record
|
23
|
+
expect(work1.depositor).to eq 'batchuser@example.com'
|
24
|
+
expect(work1.date_modified).to eq '2018-01-01'
|
25
|
+
expect(work1.label).to eq 'Work 1 Label'
|
26
|
+
expect(work1.relative_path).to eq 'tmp/files'
|
27
|
+
expect(work1.import_url).to eq 'https://example.com'
|
28
|
+
expect(work1.resource_type).to eq ['Work 1 Type']
|
29
|
+
expect(work1.creator).to eq ['Work 1 creator']
|
30
|
+
expect(work1.contributor).to eq ['Work 1 contrib']
|
31
|
+
expect(work1.description).to eq ['Desc 1']
|
32
|
+
expect(work1.keyword).to eq ['Key 1']
|
33
|
+
expect(work1.license).to eq ['Lic 1']
|
34
|
+
expect(work1.rights_statement).to eq ['RS 1']
|
35
|
+
expect(work1.publisher).to eq ['Pub 1']
|
36
|
+
expect(work1.date_created).to eq ['2018-06-06']
|
37
|
+
expect(work1.subject).to eq ['Subj 1']
|
38
|
+
|
39
|
+
# An example with 2 values
|
40
|
+
expect(work1.language).to contain_exactly('English', 'Japanese')
|
41
|
+
|
42
|
+
expect(work1.identifier).to eq ['Ident 1']
|
43
|
+
expect(work1.based_near).to eq ['Based 1']
|
44
|
+
expect(work1.related_url).to eq ['https://example.com/related']
|
45
|
+
expect(work1.bibliographic_citation).to eq ['Bib 1']
|
46
|
+
expect(work1.source).to eq ['Source 1']
|
47
|
+
|
48
|
+
# Second Record
|
49
|
+
expect(work2.depositor).to eq 'batchuser@example.com'
|
50
|
+
expect(work2.date_modified).to be_nil
|
51
|
+
expect(work2.label).to eq 'Work 2 Label'
|
52
|
+
expect(work2.relative_path).to be_nil
|
53
|
+
expect(work2.import_url).to be_nil
|
54
|
+
expect(work2.resource_type).to eq ['Work 2 Type']
|
55
|
+
expect(work2.creator).to eq []
|
56
|
+
expect(work2.contributor).to eq []
|
57
|
+
expect(work2.description).to eq ['Desc 2']
|
58
|
+
expect(work2.keyword).to eq []
|
59
|
+
expect(work2.license).to eq []
|
60
|
+
expect(work2.rights_statement).to eq []
|
61
|
+
expect(work2.publisher).to eq ['Pub 2']
|
62
|
+
expect(work2.date_created).to eq []
|
63
|
+
expect(work2.subject).to eq ['Subj 2']
|
64
|
+
expect(work2.language).to eq []
|
65
|
+
expect(work2.identifier).to eq []
|
66
|
+
expect(work2.based_near).to eq []
|
67
|
+
expect(work2.related_url).to eq []
|
68
|
+
expect(work2.bibliographic_citation).to eq []
|
69
|
+
expect(work2.source).to eq []
|
70
|
+
end
|
71
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pry' unless ENV['CI']
|
4
|
+
ENV['environment'] ||= 'test'
|
5
|
+
|
6
|
+
require 'bundler/setup'
|
7
|
+
require 'active_fedora'
|
8
|
+
require 'active_fedora/cleaner'
|
9
|
+
require 'zizia'
|
10
|
+
require 'zizia/spec'
|
11
|
+
require 'byebug'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.filter_run focus: true
|
15
|
+
config.run_all_when_everything_filtered = true
|
16
|
+
|
17
|
+
config.before(:each, clean: true) { ActiveFedora::Cleaner.clean! }
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hyrax
|
4
|
+
module BasicMetadata
|
5
|
+
def self.included(work)
|
6
|
+
work.property :label, predicate: ActiveFedora::RDF::Fcrepo::Model.downloadFilename, multiple: false
|
7
|
+
work.property :relative_path, predicate: ::RDF::URI.new('http://scholarsphere.psu.edu/ns#relativePath'), multiple: false
|
8
|
+
work.property :import_url, predicate: ::RDF::URI.new('http://scholarsphere.psu.edu/ns#importUrl'), multiple: false
|
9
|
+
work.property :resource_type, predicate: ::RDF::Vocab::DC.type
|
10
|
+
work.property :creator, predicate: ::RDF::Vocab::DC11.creator
|
11
|
+
work.property :contributor, predicate: ::RDF::Vocab::DC11.contributor
|
12
|
+
work.property :description, predicate: ::RDF::Vocab::DC11.description
|
13
|
+
work.property :keyword, predicate: ::RDF::Vocab::DC11.relation
|
14
|
+
work.property :license, predicate: ::RDF::Vocab::DC.rights
|
15
|
+
work.property :rights_statement, predicate: ::RDF::Vocab::EDM.rights
|
16
|
+
work.property :publisher, predicate: ::RDF::Vocab::DC11.publisher
|
17
|
+
work.property :date_created, predicate: ::RDF::Vocab::DC.created
|
18
|
+
work.property :subject, predicate: ::RDF::Vocab::DC11.subject
|
19
|
+
work.property :language, predicate: ::RDF::Vocab::DC11.language
|
20
|
+
work.property :identifier, predicate: ::RDF::Vocab::DC.identifier
|
21
|
+
|
22
|
+
# Note: based_near is defined differently here than in Hyrax.
|
23
|
+
work.property :based_near, predicate: ::RDF::Vocab::FOAF.based_near
|
24
|
+
|
25
|
+
work.property :related_url, predicate: ::RDF::RDFS.seeAlso
|
26
|
+
work.property :bibliographic_citation, predicate: ::RDF::Vocab::DC.bibliographicCitation
|
27
|
+
work.property :source, predicate: ::RDF::Vocab::DC.source
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hyrax
|
4
|
+
module CoreMetadata
|
5
|
+
def self.included(work)
|
6
|
+
work.property :depositor, predicate: ::RDF::URI.new('http://id.loc.gov/vocabulary/relators/dpt'), multiple: false
|
7
|
+
|
8
|
+
work.property :title, predicate: ::RDF::Vocab::DC.title
|
9
|
+
|
10
|
+
work.property :date_uploaded, predicate: ::RDF::Vocab::DC.dateSubmitted, multiple: false
|
11
|
+
|
12
|
+
work.property :date_modified, predicate: ::RDF::Vocab::DC.modified, multiple: false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
shared_context 'with a work type' do
|
4
|
+
# A work type must be defined for the default `RecordImporter` to save objects
|
5
|
+
before do
|
6
|
+
load './spec/support/hyrax/core_metadata.rb'
|
7
|
+
load './spec/support/hyrax/basic_metadata.rb'
|
8
|
+
|
9
|
+
class Work < ActiveFedora::Base
|
10
|
+
attr_accessor :visibility
|
11
|
+
attr_accessor :based_near_attributes
|
12
|
+
include ::Hyrax::CoreMetadata
|
13
|
+
include ::Hyrax::BasicMetadata
|
14
|
+
end
|
15
|
+
|
16
|
+
class User < Struct.new(:id, :user_key)
|
17
|
+
def initialize(inputs = {})
|
18
|
+
self.id = inputs[:id]
|
19
|
+
self.user_key = inputs[:user_key] || batch_user_key
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.find_by_user_key(email)
|
23
|
+
User.new(user_key: email)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.find_or_create_system_user(_email)
|
27
|
+
User.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def batch_user_key
|
31
|
+
'batchuser@example.com'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Ability
|
36
|
+
def initialize(user); end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Hyrax
|
40
|
+
def self.config
|
41
|
+
Config.new
|
42
|
+
end
|
43
|
+
|
44
|
+
class Config
|
45
|
+
def curation_concerns
|
46
|
+
[Work]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Institution
|
51
|
+
def self.name
|
52
|
+
'my_institution'
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.name_full
|
56
|
+
'my full institution name'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class UploadedFile < ActiveFedora::Base
|
61
|
+
def self.create(*)
|
62
|
+
h = Hyrax::UploadedFile.new
|
63
|
+
h.save
|
64
|
+
h
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module Actors
|
69
|
+
class Environment
|
70
|
+
attr_reader :new_object, :attributes
|
71
|
+
def initialize(new_object, _ability, attributes)
|
72
|
+
@new_object = new_object
|
73
|
+
@attributes = attributes
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Actor
|
79
|
+
def create(actor_env)
|
80
|
+
attrs = actor_env.attributes
|
81
|
+
attrs.delete(:uploaded_files)
|
82
|
+
actor_env.new_object.attributes = attrs
|
83
|
+
actor_env.new_object.save
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class CurationConcern
|
88
|
+
def self.actor
|
89
|
+
Hyrax::Actor.new
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
after do
|
96
|
+
Object.send(:remove_const, :Hyrax) if defined?(Hyrax)
|
97
|
+
Object.send(:remove_const, :Work) if defined?(Work)
|
98
|
+
Object.send(:remove_const, :User) if defined?(User)
|
99
|
+
Object.send(:remove_const, :Ability) if defined?(Ability)
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Zizia::CsvFormatValidator do
|
6
|
+
subject(:validator) { described_class.new(error_stream: []) }
|
7
|
+
let(:invalid_parser) { Zizia::CsvParser.new(file: invalid_file) }
|
8
|
+
let(:invalid_file) { File.open('spec/fixtures/bad_example.csv') }
|
9
|
+
|
10
|
+
it_behaves_like 'a Zizia::Validator' do
|
11
|
+
let(:valid_parser) { Zizia::CsvParser.new(file: valid_file) }
|
12
|
+
let(:valid_file) { File.open('spec/fixtures/example.csv') }
|
13
|
+
end
|
14
|
+
|
15
|
+
define :a_validator_error do
|
16
|
+
match do |error|
|
17
|
+
return false unless error.respond_to?(:validator)
|
18
|
+
|
19
|
+
if fields
|
20
|
+
return false if fields[:validator] && error.validator != fields[:validator]
|
21
|
+
return false if fields[:name] && error.name != fields[:name]
|
22
|
+
end
|
23
|
+
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
chain :with, :fields
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#validate' do
|
31
|
+
it 'returns a Validator::Error' do
|
32
|
+
expect(validator.validate(parser: invalid_parser))
|
33
|
+
.to contain_exactly a_validator_error
|
34
|
+
.with(validator: validator.class,
|
35
|
+
name: CSV::MalformedCSVError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
require 'tempfile'
|
6
|
+
|
7
|
+
describe Zizia::CsvParser do
|
8
|
+
subject(:parser) { described_class.new(file: file) }
|
9
|
+
let(:file) { Tempfile.new(['fake', '.csv']) }
|
10
|
+
|
11
|
+
shared_context 'with content' do
|
12
|
+
let(:csv_content) do
|
13
|
+
<<-EOS
|
14
|
+
title,description,date created
|
15
|
+
The Moomins and the Great Flood,"The Moomins and the Great Flood (Swedish: Småtrollen och den stora översvämningen, literally The Little Trolls and the Great Flood) is a book written by Finnish author Tove Jansson in 1945, during the end of World War II. It was the first book to star the Moomins, but is often seen as a prelude to the main Moomin books, as most of the main characters are introduced in the next book.",1945
|
16
|
+
Comet in Moominland,"Comet in Moominland is the second in Tove Jansson's series of Moomin books. Published in 1946, it marks the first appearance of several main characters, like Snufkin and the Snork Maiden.",1946
|
17
|
+
EOS
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:record_count) { 2 }
|
21
|
+
|
22
|
+
before do
|
23
|
+
file.write(csv_content)
|
24
|
+
file.rewind
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it_behaves_like 'a Zizia::Parser' do
|
29
|
+
include_context 'with content'
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'matches .csv files' do
|
33
|
+
expect(Zizia::Parser.for(file: file)).to be_a described_class
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#records' do
|
37
|
+
context 'with valid content' do
|
38
|
+
include_context 'with content'
|
39
|
+
|
40
|
+
it 'has the correct titles' do
|
41
|
+
expect(parser.records.map(&:title))
|
42
|
+
.to contain_exactly(['The Moomins and the Great Flood'],
|
43
|
+
['Comet in Moominland'])
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'has correct other fields' do
|
47
|
+
expect(parser.records.map(&:date_created)).to contain_exactly(['1945'], ['1946'])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'with invalid file' do
|
52
|
+
let(:file) { File.open('spec/fixtures/bad_example.csv') }
|
53
|
+
|
54
|
+
it 'is empty' do
|
55
|
+
expect(parser.records.to_a).to be_empty
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#validate' do
|
61
|
+
it 'is valid' do
|
62
|
+
expect(parser.validate).to be_truthy
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with invalid file' do
|
66
|
+
let(:file) { File.open('spec/fixtures/bad_example.csv') }
|
67
|
+
|
68
|
+
it 'is invalid' do
|
69
|
+
expect(parser.validate).to be_falsey
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'zizia/streams/formatted_message_stream'
|
5
|
+
|
6
|
+
describe Zizia::FormattedMessageStream do
|
7
|
+
subject(:stream) { described_class.new(stream: fake_stream) }
|
8
|
+
let(:fake_stream) { [] }
|
9
|
+
|
10
|
+
it_behaves_like 'a Zizia::MessageStream'
|
11
|
+
|
12
|
+
describe '#stream' do
|
13
|
+
subject(:stream) { described_class.new }
|
14
|
+
|
15
|
+
it 'is STDOUT by default' do
|
16
|
+
expect(stream.stream).to eq STDOUT
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#<<' do
|
21
|
+
it 'appends newlines by default' do
|
22
|
+
expect { stream << 'moomin' }
|
23
|
+
.to change { fake_stream }
|
24
|
+
.to contain_exactly("moomin\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'uses other % formatters' do
|
28
|
+
stream.formatter = "!!!%s!!!"
|
29
|
+
|
30
|
+
expect { stream << 'moomin' }
|
31
|
+
.to change { fake_stream }
|
32
|
+
.to contain_exactly('!!!moomin!!!')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|