-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create the import_chapter
method
#58
Merged
Merged
Changes from 16 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
33cf2ff
Write and test the `@book.import_chapter(num)` method
dsomel21 6a7687e
Start writing specs
dsomel21 825856f
Fix most of the tests
dsomel21 319ff0c
Remove puts
dsomel21 81edc6d
Spec for aborting when updating name
dsomel21 a4f7af6
Write better tests and refactor.
dsomel21 a01c46b
HEAVY REFACTOR
dsomel21 dbdcf44
Linting and rubocop ignoring stuff
dsomel21 0e01c94
MORE RUBOCOP
dsomel21 d1f415a
Add fallback to 'Translation_EN' if 'Tuk_Translation_EN' is blank in …
dsomel21 49a7e8a
Added a way to handle differentiating Tuk content
dsomel21 5493e3b
Merge remote-tracking branch 'origin/main' into 57-create-chapter-csv…
dsomel21 5b7aec1
Minor puts message improvement!
dsomel21 de79b39
Merge remote-tracking branch 'origin/main' into 57-create-chapter-csv…
dsomel21 14d1b2c
#57 book_spec.rb passes
dsomel21 64ca1ba
#57 move stuff into a Service object
dsomel21 44c5050
Linting
dsomel21 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
# frozen_string_literal: true | ||
|
||
class ChapterImporterService | ||
attr_reader :book, :chapter_number, :pastel, :prompt, :chapter | ||
|
||
def initialize(book, chapter_number) | ||
@book = book | ||
@chapter_number = chapter_number | ||
@pastel = Pastel.new | ||
@prompt = TTY::Prompt.new | ||
end | ||
|
||
def call | ||
ensure_chapter_exists! | ||
ActiveRecord::Base.transaction do | ||
each_csv_row do |row| | ||
process_row(row) | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
def each_csv_row(&) | ||
blob = chapter.csv_rows | ||
blob.each(&) | ||
end | ||
|
||
def ensure_chapter_exists! | ||
@chapter = book.chapters.find_by(:number => chapter_number) | ||
raise "Chapter not found: #{chapter_number}" unless @chapter | ||
end | ||
|
||
def process_row(row) | ||
validate_and_update_chapter_title(row) | ||
process_pauri(row) | ||
process_tuk(row) | ||
create_tuk_translation(row) | ||
create_pauri_translation(row) | ||
end | ||
|
||
def validate_and_update_chapter_title(row) | ||
chapter_name = row['Chapter_Name'].try(:strip) | ||
return if chapter.title == chapter_name | ||
|
||
message = "The name in Book #{book.sequence}, Chapter #{chapter_number} is " + | ||
pastel.bold('presently') + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: You could use string interpolation here instead of + |
||
" '#{chapter.title}'. The CSV says '#{chapter_name}'." | ||
prompt.say(message, :color => :yellow) | ||
answer = prompt.yes?("Do you want to continue and update this title to '#{chapter_name}'?") | ||
raise 'Aborted by user' unless answer | ||
|
||
chapter.update(:title => chapter_name) | ||
Rails.logger.debug pastel.green("✓ Chapter #{chapter_number}'s title updated to '#{chapter_name}'") | ||
end | ||
|
||
def process_pauri(row) | ||
pauri_number = row['Pauri_Number'].to_i | ||
@pauri = chapter.pauris.find_by(:number => pauri_number) | ||
|
||
raise "Pauri not found: #{pauri_number}" if @pauri.nil? | ||
end | ||
|
||
def process_tuk(row) | ||
tuk = row['Tuk'].try(:strip) | ||
tuk_number = row['Tuk_Number'].to_i | ||
@tuk = @pauri.tuks.find_by(:sequence => tuk_number) | ||
|
||
raise "Tuk #{tuk_number} not found: #{tuk}" if @tuk.nil? | ||
|
||
return if @tuk.original_content == tuk | ||
|
||
diff = Diffy::Diff.new(@tuk.original_content, tuk, :include_diff_info => true).to_s(:color) | ||
Rails.logger.debug diff | ||
|
||
choices = [ | ||
"Keep the NEW one from the CSV (update the original) :: #{tuk}", | ||
pastel.red("Keep the original :: #{@tuk.original_content}") | ||
] | ||
|
||
selected_choice = prompt.select('Choose an option:', choices) | ||
case selected_choice | ||
when choices[0] | ||
@tuk.update(:original_content => tuk) | ||
Rails.logger.debug pastel.green("✓ `Tuk` `original_content` updated to #{tuk} - For #{@pauri.number}.#{tuk_number}") | ||
when choices[1] | ||
Rails.logger.debug pastel.red("x Keeping the original `Tuk` `original_content` - For #{@pauri.number}.#{tuk_number}") | ||
end | ||
end | ||
|
||
def create_tuk_translation(row) | ||
tuk_translation_en = row['Tuk_Translation_EN'].try(:strip) || row['Translation_EN'].try(:strip) | ||
return if tuk_translation_en.blank? | ||
|
||
# If there's a Pauri translation and a Tuk translation, ask what to do | ||
if @pauri.translation.present? | ||
choices = [ | ||
'Continue with the `TukTranslation` and KEEP the `PauriTranslation`, too!', | ||
'Destroy the existing `PauriTranslation`, and continue with only the `TukTranslation`', | ||
pastel.red('Abort') | ||
] | ||
selected_choice = prompt.select('Choose an option:', choices) | ||
|
||
case selected_choice | ||
when choices[0] | ||
upsert_tuk_translation(tuk_translation_en, row['Assigned_Singh'].try(:strip)) | ||
when choices[1] | ||
upsert_tuk_translation(tuk_translation_en, row['Assigned_Singh'].try(:strip)) | ||
@pauri.translation.destroy | ||
when choices[2] | ||
raise 'Aborted by user' | ||
end | ||
else | ||
upsert_tuk_translation(tuk_translation_en, row['Assigned_Singh'].try(:strip)) | ||
end | ||
end | ||
|
||
def upsert_tuk_translation(translation, translator) | ||
@tuk_translation = @tuk.translation || TukTranslation.new(:tuk_id => @tuk.id) | ||
@tuk_translation.update(:en_translation => translation, :en_translator => translator) | ||
Rails.logger.debug pastel.green("✓ `TukTranslation` created or updated for Tuk #{translation} - Pauri # #{@pauri.number}") | ||
end | ||
|
||
def create_pauri_translation(row) | ||
pauri_translation_en = row['Pauri_Translation_EN'].try(:strip) | ||
return if pauri_translation_en.blank? | ||
|
||
pauri_translation = @pauri.translation || PauriTranslation.new(:pauri_id => @pauri.id) | ||
pauri_translation.update(:en_translation => pauri_translation_en, :en_translator => row['Assigned_Singh'].try(:strip)) | ||
Rails.logger.debug pastel.green("✓ `PauriTranslation` created or updated for Pauri # #{@pauri.number}") | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
# rubocop:disable RSpec/NestedGroups, RSpec/MultipleExpectations | ||
# frozen_string_literal: true | ||
|
||
require 'rails_helper' | ||
require 'csv' | ||
|
||
RSpec.describe Book do | ||
let(:book) { create(:book) } | ||
|
||
describe '#import_chapter' do | ||
context 'when the `chapter.number` is invalid' do | ||
it 'raises an error if the `chapter_number` does not exist in `book`' do | ||
expect { book.import_chapter(99) }.to raise_error(RuntimeError, /Chapter not found: 99/) | ||
end | ||
|
||
it 'raises an error if the CSV does not exist' do | ||
# Create the `Chapter` row only! Not the CSV. | ||
create(:chapter, :book => book, :number => 100) | ||
expect { book.import_chapter(100) }.to raise_error(RuntimeError, %r{CSV file lib/imports/1/100\.csv not found}) | ||
end | ||
end | ||
|
||
context 'when the `chapter_number` is valid' do | ||
csv_content = <<~CSV | ||
Chapter_Number,Chapter_Name,Chhand_Type ,Tuk,Pauri_Number,Tuk_Number,Pauri_Translation_EN,Translation_EN ,Footnotes,Custom_Footnotes,Extended_Ref ,Assigned_Singh,Status,Extended_Meaning | ||
CSV | ||
|
||
csv_rows = CSV.parse(csv_content, :headers => true) | ||
let(:chapter) { create(:chapter, :book => book) } | ||
|
||
it 'does not raise an error' do | ||
file_path = "lib/imports/#{book.sequence}/#{chapter.number}.csv" | ||
|
||
allow(File).to receive(:exist?).with(file_path).and_return(true) | ||
allow(CSV).to receive(:foreach).with(file_path, :headers => true).and_return(csv_rows) | ||
|
||
expect { book.import_chapter(chapter.number) }.not_to raise_error | ||
end | ||
end | ||
|
||
context 'when given valid input and CSV' do | ||
let(:chapter_number) { 99 } | ||
let(:chapter_title) { 'ਇਸ਼੍ਟ ਦੇਵ-ਸ਼੍ਰੀ ਅਕਾਲ ਪੁਰਖ-ਮੰਗਲ' } | ||
let(:csv_content) do | ||
<<~CSV | ||
Chapter_Number,Chapter_Name,Chhand_Type ,Tuk,Pauri_Number,Tuk_Number,Pauri_Translation_EN,Translation_EN ,Footnotes,Custom_Footnotes,Extended_Ref ,Assigned_Singh,Status,Extended_Meaning | ||
99,ਇਸ਼੍ਟ ਦੇਵ-ਸ਼੍ਰੀ ਅਕਾਲ ਪੁਰਖ-ਮੰਗਲ,ਦੋਹਰਾ,"ਤੀਨੋ ਕਾਲ ਅਲਿਪਤ ਰਹਿ, ਖੋਜੈਂ ਜਾਂਹਿ ਪ੍ਰਬੀਨ",1,1,,,,,,,, | ||
99,ਇਸ਼੍ਟ ਦੇਵ-ਸ਼੍ਰੀ ਅਕਾਲ ਪੁਰਖ-ਮੰਗਲ,ਦੋਹਰਾ,"ਬੀਨਤਿ ਸਚਿਦਾਨੰਦ ਤ੍ਰੈ, ਜਾਨਹਿਂ ਮਰਮ ਰਤੀ ਨ",1,2,,,,,,,, | ||
CSV | ||
end | ||
|
||
let(:chapter) { create(:chapter, :number => chapter_number, :book => book, :title => chapter_title) } | ||
let(:chhand_type) { create(:chhand_type, :name => 'ਦੋਹਰਾ') } | ||
let(:chhand) { create(:chhand, :chhand_type => chhand_type, :chapter => chapter) } | ||
let(:pauri) { create(:pauri, :chapter => chapter, :chhand => chhand, :number => 1) } | ||
let(:prompt) { instance_double(TTY::Prompt) } | ||
|
||
before do | ||
# Initialize mocks for TTY::Prompt | ||
allow(TTY::Prompt).to receive(:new).and_return(prompt) | ||
allow(prompt).to receive(:say) | ||
|
||
# Associations for the chapter - This one reflects out mock `csv_content` | ||
create(:tuk, :pauri => pauri, :chapter => chapter, :original_content => 'ਤੀਨੋ ਕਾਲ ਅਲਿਪਤ ਰਹਿ, ਖੋਜੈਂ ਜਾਂਹਿ ਪ੍ਰਬੀਨ', :sequence => 1) | ||
create(:tuk, :pauri => pauri, :chapter => chapter, :original_content => 'ਬੀਨਤਿ ਸਚਿਦਾਨੰਦ ਤ੍ਰੈ, ਜਾਨਹਿਂ ਮਰਮ ਰਤੀ ਨ', :sequence => 2) | ||
|
||
# Mocking the CSV data | ||
allow(book.chapters).to receive(:find_by).with(:number => chapter_number).and_return(chapter) | ||
allow(chapter).to receive(:csv_rows).and_return(CSV.parse(csv_content, :headers => true)) | ||
end | ||
|
||
context 'when prompted to update `chapter.title`' do | ||
it 'does not prompt user if the `chapter.title` is unchanged' do | ||
allow(prompt).to receive(:yes?) | ||
book.import_chapter(chapter_number) | ||
expect(prompt).not_to have_received(:yes?) | ||
|
||
expect(chapter.reload.title).to eq(chapter_title) | ||
end | ||
|
||
it 'updates the `chapter.title` if user confirms' do | ||
# Change the `chapter.title` so it is different than the one in CSV | ||
chapter.update(:title => 'Different title') | ||
|
||
allow(prompt).to receive(:yes?).and_return(true) | ||
book.import_chapter(chapter_number) | ||
|
||
expect(prompt).to have_received(:yes?).with("Do you want to continue and update this title to '#{chapter_title}'?") | ||
expect(chapter.reload.title).to eq(chapter_title) | ||
end | ||
|
||
it 'aborts and does not update the chapter title if user declines' do | ||
# Change the `chapter.title` so it is different than the one in CSV | ||
chapter.update(:title => 'Something Else - Suraj Suraj Suraj') | ||
allow(prompt).to receive(:yes?).and_return(false) | ||
expect { book.import_chapter(chapter_number) }.to raise_error(RuntimeError, 'Aborted by user') | ||
end | ||
end | ||
|
||
context 'when `chapter` associations do not exist' do | ||
it 'raises an error when `pauri` is nil' do | ||
pauri.destroy | ||
expect { book.import_chapter(chapter_number) }.to raise_error(StandardError, /Pauri not found/) | ||
end | ||
|
||
it 'raises an error when `tuks` are nil' do | ||
Tuk.destroy_all | ||
expect { book.import_chapter(chapter_number) }.to raise_error(StandardError, /Tuk 1 not found/) | ||
end | ||
|
||
it 'raises an error when 2nd `tuk` is missing' do | ||
chapter.tuks.second.destroy | ||
expect { book.import_chapter(chapter_number) }.to raise_error(StandardError, /Tuk 2 not found/) | ||
end | ||
end | ||
|
||
# TODO: Write tests for Translations, Footnotes, etc. | ||
# TODO: and write tests for the TTY stuff | ||
end | ||
end | ||
end | ||
|
||
# rubocop:enable RSpec/NestedGroups, RSpec/MultipleExpectations |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't think I needed this, but apparently I do 🤷🏾