anki_record 0.2.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +13 -2
  3. data/CHANGELOG.md +37 -9
  4. data/Gemfile +3 -1
  5. data/Gemfile.lock +10 -2
  6. data/README.md +120 -35
  7. data/anki_record.gemspec +1 -5
  8. data/lib/anki_record/anki_package/anki_package.rb +237 -0
  9. data/lib/anki_record/card/card.rb +108 -0
  10. data/lib/anki_record/card/card_attributes.rb +39 -0
  11. data/lib/anki_record/card_template/card_template.rb +64 -0
  12. data/lib/anki_record/card_template/card_template_attributes.rb +69 -0
  13. data/lib/anki_record/collection/collection.rb +182 -0
  14. data/lib/anki_record/collection/collection_attributes.rb +35 -0
  15. data/lib/anki_record/database_setup_constants.rb +88 -0
  16. data/lib/anki_record/deck/deck.rb +99 -0
  17. data/lib/anki_record/deck/deck_attributes.rb +30 -0
  18. data/lib/anki_record/deck/deck_defaults.rb +19 -0
  19. data/lib/anki_record/{deck_options_group.rb → deck_options_group/deck_options_group.rb} +12 -31
  20. data/lib/anki_record/deck_options_group/deck_options_group_attributes.rb +23 -0
  21. data/lib/anki_record/helpers/checksum_helper.rb +10 -11
  22. data/lib/anki_record/helpers/data_query_helper.rb +15 -0
  23. data/lib/anki_record/helpers/shared_constants_helper.rb +6 -6
  24. data/lib/anki_record/helpers/time_helper.rb +18 -13
  25. data/lib/anki_record/note/note.rb +178 -0
  26. data/lib/anki_record/note/note_attributes.rb +56 -0
  27. data/lib/anki_record/note_field/note_field.rb +62 -0
  28. data/lib/anki_record/note_field/note_field_attributes.rb +39 -0
  29. data/lib/anki_record/note_field/note_field_defaults.rb +19 -0
  30. data/lib/anki_record/note_type/note_type.rb +161 -0
  31. data/lib/anki_record/note_type/note_type_attributes.rb +80 -0
  32. data/lib/anki_record/note_type/note_type_defaults.rb +38 -0
  33. data/lib/anki_record/version.rb +1 -1
  34. data/lib/anki_record.rb +1 -16
  35. metadata +26 -16
  36. data/lib/anki_record/anki_package.rb +0 -194
  37. data/lib/anki_record/card.rb +0 -75
  38. data/lib/anki_record/card_template.rb +0 -105
  39. data/lib/anki_record/collection.rb +0 -105
  40. data/lib/anki_record/db/anki_schema_definition.rb +0 -77
  41. data/lib/anki_record/db/clean_collection21_record.rb +0 -10
  42. data/lib/anki_record/db/clean_collection2_record.rb +0 -10
  43. data/lib/anki_record/deck.rb +0 -101
  44. data/lib/anki_record/note.rb +0 -135
  45. data/lib/anki_record/note_field.rb +0 -84
  46. data/lib/anki_record/note_type.rb +0 -233
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnkiRecord
4
+ ##
5
+ # Module with the NoteField class's attribute readers, writers, and accessors.
6
+ module NoteFieldAttributes
7
+ ##
8
+ # The field's note type.
9
+ attr_reader :note_type
10
+
11
+ ##
12
+ # The field's name.
13
+ attr_accessor :name
14
+
15
+ ##
16
+ # A boolean that indicates if the field is sticky.
17
+ attr_accessor :sticky
18
+
19
+ ##
20
+ # A boolean that indicates if the field is right to left.
21
+ attr_accessor :right_to_left
22
+
23
+ ##
24
+ # The field's font style used when editing.
25
+ attr_accessor :font_style
26
+
27
+ ##
28
+ # The field's font size used when editing.
29
+ attr_accessor :font_size
30
+
31
+ ##
32
+ # The field's description.
33
+ attr_accessor :description
34
+
35
+ ##
36
+ # 0 for the first field of the note type, 1 for the second, etc.
37
+ attr_reader :ordinal_number
38
+ end
39
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnkiRecord
4
+ module NoteFieldDefaults # :nodoc:
5
+ private
6
+
7
+ def default_field_font_style
8
+ "Arial"
9
+ end
10
+
11
+ def default_field_font_size
12
+ 20
13
+ end
14
+
15
+ def default_field_description
16
+ ""
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../card_template/card_template"
4
+ require_relative "../helpers/shared_constants_helper"
5
+ require_relative "../helpers/time_helper"
6
+ require_relative "../note_field/note_field"
7
+ require_relative "note_type_attributes"
8
+ require_relative "note_type_defaults"
9
+
10
+ module AnkiRecord
11
+ ##
12
+ # NoteType represents an Anki note type (also called a model).
13
+ #
14
+ # The attributes are documented in the NoteTypeAttributes module.
15
+ class NoteType
16
+ include Helpers::SharedConstantsHelper
17
+ include Helpers::TimeHelper
18
+ include NoteTypeAttributes
19
+ include NoteTypeDefaults
20
+
21
+ NOTE_TYPES_WITHOUT_TAGS_AND_VERS_VALUES = ["Basic", "Basic (and reversed card)",
22
+ "Basic (optional reversed card)", "Basic (type in the answer)"].freeze
23
+
24
+ def initialize(collection:, name: nil, args: nil)
25
+ raise ArgumentError unless (name && args.nil?) || (args && args["name"])
26
+
27
+ @collection = collection
28
+
29
+ if args
30
+ setup_note_type_instance_variables_from_existing(args: args)
31
+ else
32
+ setup_instance_variables_for_new_note_type(name: name)
33
+ end
34
+
35
+ @collection.add_note_type self
36
+ save
37
+ end
38
+
39
+ ##
40
+ # Saves the note type to the collection.anki21 database
41
+ def save
42
+ collection_models_hash = collection.models_json
43
+ collection_models_hash[@id] = to_h
44
+ sql = "update col set models = ? where id = ?"
45
+ collection.anki_package.prepare(sql).execute([JSON.generate(collection_models_hash), collection.id])
46
+ end
47
+
48
+ def to_h # :nodoc:
49
+ self_to_h = { id: @id, name: @name, type: @cloze ? 1 : 0,
50
+ mod: @last_modified_timestamp, usn: @usn, sortf: @sort_field, did: @deck_id,
51
+ tmpls: @card_templates.map(&:to_h), flds: @note_fields.map(&:to_h), css: @css,
52
+ latexPre: @latex_preamble, latexPost: @latex_postamble, latexsvg: @latex_svg,
53
+ req: @req }
54
+ self_to_h.merge({ tags: @tags, vers: @vers }) unless NOTE_TYPES_WITHOUT_TAGS_AND_VERS_VALUES.include?(@name)
55
+ self_to_h
56
+ end
57
+
58
+ ##
59
+ # Returns the note type object's card template with name +name+ or nil if it is not found
60
+ def find_card_template_by(name:)
61
+ card_templates.find { |template| template.name == name }
62
+ end
63
+
64
+ ##
65
+ # Returns an array of the note type's fields' names ordered by field ordinal values.
66
+ def field_names_in_order
67
+ @note_fields.sort_by(&:ordinal_number).map(&:name)
68
+ end
69
+
70
+ def snake_case_field_names # :nodoc:
71
+ field_names_in_order.map { |field_name| field_name.downcase.gsub(" ", "_") }
72
+ end
73
+
74
+ ##
75
+ # Returns the name of the note type's field used to sort notes in the browser.
76
+ def sort_field_name
77
+ @note_fields.find { |field| field.ordinal_number == @sort_field }&.name
78
+ end
79
+
80
+ def snake_case_sort_field_name # :nodoc:
81
+ sort_field_name.downcase.gsub(" ", "_")
82
+ end
83
+
84
+ ##
85
+ # Returns allowed field_name values in {{field_name}} in the question format.
86
+ def allowed_card_template_question_format_field_names
87
+ allowed = field_names_in_order
88
+ cloze ? allowed + field_names_in_order.map { |field_name| "cloze:#{field_name}" } : allowed
89
+ end
90
+
91
+ ##
92
+ # Returns allowed field_name values in {{field_name}} in the answer format.
93
+ def allowed_card_template_answer_format_field_names
94
+ allowed_card_template_question_format_field_names + ["FrontSide"]
95
+ end
96
+
97
+ def add_note_field(note_field) # :nodoc:
98
+ raise ArgumentError unless note_field.instance_of?(AnkiRecord::NoteField)
99
+
100
+ @note_fields << note_field
101
+ end
102
+
103
+ def add_card_template(card_template) # :nodoc:
104
+ raise ArgumentError unless card_template.instance_of?(AnkiRecord::CardTemplate)
105
+
106
+ @card_templates << card_template
107
+ end
108
+
109
+ private
110
+
111
+ def setup_note_type_instance_variables_from_existing(args:)
112
+ setup_collaborator_object_instance_variables_from_existing(args: args)
113
+ setup_simple_instance_variables_from_existing(args: args)
114
+ end
115
+
116
+ def setup_collaborator_object_instance_variables_from_existing(args:)
117
+ @note_fields = []
118
+ args["flds"].each { |fld| NoteField.new(note_type: self, args: fld) }
119
+ @card_templates = []
120
+ args["tmpls"].each { |tmpl| CardTemplate.new(note_type: self, args: tmpl) }
121
+ end
122
+
123
+ def setup_simple_instance_variables_from_existing(args:)
124
+ %w[id name usn css req tags vers].each do |note_type_attribute|
125
+ instance_variable_set "@#{note_type_attribute}", args[note_type_attribute]
126
+ end
127
+ @cloze = args["type"] == 1
128
+ @last_modified_timestamp = args["mod"]
129
+ @sort_field = args["sortf"]
130
+ @deck_id = args["did"]
131
+ @latex_preamble = args["latexPre"]
132
+ @latex_postamble = args["latexPost"]
133
+ @latex_svg = args["latexsvg"]
134
+ end
135
+
136
+ def setup_instance_variables_for_new_note_type(name:)
137
+ @name = name
138
+ @cloze = false
139
+ setup_collaborator_object_instance_variables_for_new_note_type
140
+ setup_simple_instance_variables_for_new_note_type
141
+ end
142
+
143
+ def setup_collaborator_object_instance_variables_for_new_note_type
144
+ @note_fields = []
145
+ @card_templates = []
146
+ end
147
+
148
+ def setup_simple_instance_variables_for_new_note_type
149
+ @id = milliseconds_since_epoch
150
+ @last_modified_timestamp = seconds_since_epoch
151
+ @usn = NEW_OBJECT_USN
152
+ @sort_field = default_note_type_sort_field
153
+ @deck_id = @tags = @vers = nil
154
+ @css = default_css
155
+ @latex_preamble = default_latex_preamble
156
+ @latex_postamble = default_latex_postamble
157
+ @latex_svg = false
158
+ @req = []
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnkiRecord
4
+ ##
5
+ # Module with the NoteType class's attribute readers, writers, and accessors.
6
+ module NoteTypeAttributes
7
+ ##
8
+ # The note type's collection object.
9
+ attr_reader :collection
10
+
11
+ ##
12
+ # The note type's id.
13
+ attr_reader :id
14
+
15
+ ##
16
+ # The note type's name.
17
+ attr_accessor :name
18
+
19
+ ##
20
+ # A boolean that indicates if this note type is a cloze-deletion note type.
21
+ attr_accessor :cloze
22
+
23
+ ##
24
+ # The number of seconds since the 1970 epoch at which the note type was last modified.
25
+ attr_reader :last_modified_timestamp
26
+
27
+ ##
28
+ # The note type's update sequence number.
29
+ attr_reader :usn
30
+
31
+ ##
32
+ # The note type's sort field.
33
+ attr_reader :sort_field
34
+
35
+ ##
36
+ # The note type's CSS.
37
+ attr_accessor :css
38
+
39
+ ##
40
+ # The note type's LaTeX preamble.
41
+ attr_reader :latex_preamble
42
+
43
+ ##
44
+ # The note type's LaTeX postamble.
45
+ attr_reader :latex_postamble
46
+
47
+ ##
48
+ # The note type's card template objects, as an array.
49
+ attr_reader :card_templates
50
+
51
+ ##
52
+ # The note type's field objects, as an array.
53
+ attr_reader :note_fields
54
+
55
+ ##
56
+ # The note type's deck's id.
57
+ attr_reader :deck_id
58
+
59
+ ##
60
+ # The note type's deck.
61
+ def deck
62
+ return nil unless @deck_id
63
+
64
+ @collection.find_deck_by id: @deck_id
65
+ end
66
+
67
+ ##
68
+ # Sets the note type's deck object.
69
+ def deck=(deck)
70
+ unless deck.instance_of?(AnkiRecord::Deck)
71
+ raise ArgumentError,
72
+ "You can only set this attribute to an instance of AnkiRecord::Deck."
73
+ end
74
+
75
+ @deck_id = deck.id
76
+ end
77
+
78
+ attr_reader :latex_svg, :tags, :req, :vers
79
+ end
80
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnkiRecord
4
+ module NoteTypeDefaults # :nodoc:
5
+ private
6
+
7
+ def default_note_type_sort_field
8
+ 0
9
+ end
10
+
11
+ def default_css
12
+ <<~CSS
13
+ .card {
14
+ color: black;
15
+ background-color: transparent;
16
+ text-align: center;
17
+ }
18
+ CSS
19
+ end
20
+
21
+ def default_latex_preamble
22
+ <<~LATEX_PRE
23
+ \\documentclass[12pt]{article}
24
+ \\special{papersize=3in,5in}
25
+ \\usepackage{amssymb,amsmath}
26
+ \\pagestyle{empty}
27
+ \\setlength{\\parindent}{0in}
28
+ \\begin{document}
29
+ LATEX_PRE
30
+ end
31
+
32
+ def default_latex_postamble
33
+ <<~LATEX_POST
34
+ \\end{document}
35
+ LATEX_POST
36
+ end
37
+ end
38
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AnkiRecord
4
- VERSION = "0.2.0" # :nodoc:
4
+ VERSION = "0.3.1" # :nodoc:
5
5
  end
data/lib/anki_record.rb CHANGED
@@ -3,24 +3,9 @@
3
3
  require "sqlite3"
4
4
  require "zip"
5
5
 
6
- require_relative "anki_record/anki_package"
6
+ require_relative "anki_record/anki_package/anki_package"
7
7
  require_relative "anki_record/version"
8
8
 
9
- ##
10
- # This module is the namespace for all AnkiRecord classes:
11
- # - AnkiPackage
12
- # - Card
13
- # - CardTemplate
14
- # - Collection
15
- # - DeckOptionsGroup
16
- # - Deck
17
- # - Note
18
- # - NoteField
19
- # - NoteType
20
- #
21
- # And modules:
22
- # - SharedConstantsHelper
23
- # - TimeHelper
24
9
  module AnkiRecord
25
10
  class Error < StandardError; end # :nodoc:
26
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anki_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Rego
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-03-05 00:00:00.000000000 Z
11
+ date: 2023-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -38,8 +38,8 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.3'
41
- description: " This Ruby library, which is currently in development, will provide
42
- an interface to inspect, update, and create Anki SQLite3 databases (*.apkg files).\n"
41
+ description: " A Ruby library which provides a programmatic interface to Anki flashcard
42
+ decks (.apkg files/zipped Anki SQLite databases).\n"
43
43
  email:
44
44
  - regoky@outlook.com
45
45
  executables: []
@@ -57,21 +57,31 @@ files:
57
57
  - Rakefile
58
58
  - anki_record.gemspec
59
59
  - lib/anki_record.rb
60
- - lib/anki_record/anki_package.rb
61
- - lib/anki_record/card.rb
62
- - lib/anki_record/card_template.rb
63
- - lib/anki_record/collection.rb
64
- - lib/anki_record/db/anki_schema_definition.rb
65
- - lib/anki_record/db/clean_collection21_record.rb
66
- - lib/anki_record/db/clean_collection2_record.rb
67
- - lib/anki_record/deck.rb
68
- - lib/anki_record/deck_options_group.rb
60
+ - lib/anki_record/anki_package/anki_package.rb
61
+ - lib/anki_record/card/card.rb
62
+ - lib/anki_record/card/card_attributes.rb
63
+ - lib/anki_record/card_template/card_template.rb
64
+ - lib/anki_record/card_template/card_template_attributes.rb
65
+ - lib/anki_record/collection/collection.rb
66
+ - lib/anki_record/collection/collection_attributes.rb
67
+ - lib/anki_record/database_setup_constants.rb
68
+ - lib/anki_record/deck/deck.rb
69
+ - lib/anki_record/deck/deck_attributes.rb
70
+ - lib/anki_record/deck/deck_defaults.rb
71
+ - lib/anki_record/deck_options_group/deck_options_group.rb
72
+ - lib/anki_record/deck_options_group/deck_options_group_attributes.rb
69
73
  - lib/anki_record/helpers/checksum_helper.rb
74
+ - lib/anki_record/helpers/data_query_helper.rb
70
75
  - lib/anki_record/helpers/shared_constants_helper.rb
71
76
  - lib/anki_record/helpers/time_helper.rb
72
- - lib/anki_record/note.rb
73
- - lib/anki_record/note_field.rb
74
- - lib/anki_record/note_type.rb
77
+ - lib/anki_record/note/note.rb
78
+ - lib/anki_record/note/note_attributes.rb
79
+ - lib/anki_record/note_field/note_field.rb
80
+ - lib/anki_record/note_field/note_field_attributes.rb
81
+ - lib/anki_record/note_field/note_field_defaults.rb
82
+ - lib/anki_record/note_type/note_type.rb
83
+ - lib/anki_record/note_type/note_type_attributes.rb
84
+ - lib/anki_record/note_type/note_type_defaults.rb
75
85
  - lib/anki_record/version.rb
76
86
  homepage: https://github.com/KyleRego/anki_record
77
87
  licenses:
@@ -1,194 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pry"
4
- require "pathname"
5
-
6
- require_relative "card"
7
- require_relative "note"
8
-
9
- require_relative "db/anki_schema_definition"
10
- require_relative "db/clean_collection2_record"
11
- require_relative "db/clean_collection21_record"
12
- require_relative "collection"
13
-
14
- module AnkiRecord
15
- ##
16
- # Represents an Anki SQLite3 package/database
17
- #
18
- # Use ::new to create a new object or ::open to create an object from an existing one
19
- class AnkiPackage
20
- NAME_ERROR_MESSAGE = "The name argument must be a string without spaces."
21
- PATH_ERROR_MESSAGE = "*No .apkg file was found at the given path."
22
- STANDARD_ERROR_MESSAGE = <<-MSG
23
- An error occurred.
24
- The temporary *.anki21 database has been deleted.
25
- No *.apkg zip file has been saved.
26
- MSG
27
-
28
- private_constant :NAME_ERROR_MESSAGE, :PATH_ERROR_MESSAGE, :STANDARD_ERROR_MESSAGE
29
-
30
- ##
31
- # The collection object of the package
32
- attr_reader :collection
33
-
34
- ##
35
- # Creates a new object which represents an Anki SQLite3 database
36
- #
37
- # This method takes an optional block argument.
38
- #
39
- # When a block argument is used, execution is yielded to the block.
40
- # After the block executes, the temporary files are zipped into the +name+.apkg file
41
- # which is saved in +directory+. +directory+ is the current working directory by default.
42
- # If the block throws a runtime error, the temporary files are deleted but the zip file is not created.
43
- #
44
- # When no block argument is used, #zip must be called explicitly at the end of your script.
45
- def initialize(name:, directory: Dir.pwd, &closure)
46
- setup_package_instance_variables(name: name, directory: directory)
47
-
48
- execute_closure_and_zip(self, &closure) if block_given?
49
- end
50
-
51
- ##
52
- # Executes a raw SQL statement against the *.anki21 database
53
- #
54
- # Do not use this to execute data definition language SQL statements
55
- # (i.e. do not create, alter, or drop tables or indexes)
56
- # unless you have a good reason to change the database schema.
57
- def execute(raw_sql_string)
58
- @anki21_database.execute raw_sql_string
59
- end
60
-
61
- private
62
-
63
- def execute_closure_and_zip(object_to_yield, &closure)
64
- closure.call(object_to_yield)
65
- rescue StandardError => e
66
- destroy_temporary_directory
67
- puts_error_and_standard_message(error: e)
68
- else
69
- zip
70
- end
71
-
72
- def setup_package_instance_variables(name:, directory:)
73
- @name = check_name_is_valid(name: name)
74
- @directory = directory # TODO: check directory is valid
75
- @tmpdir = Dir.mktmpdir
76
- @tmp_files = []
77
- @anki21_database = setup_anki21_database_object
78
- @anki2_database = setup_anki2_database_object
79
- @media_file = setup_media
80
- @collection = Collection.new(anki_package: self)
81
- end
82
-
83
- def check_name_is_valid(name:)
84
- raise ArgumentError, NAME_ERROR_MESSAGE unless name.instance_of?(String) && !name.empty? && !name.include?(" ")
85
-
86
- name.end_with?(".apkg") ? name[0, name.length - 5] : name
87
- end
88
-
89
- def setup_anki21_database_object
90
- anki21_file_name = "collection.anki21"
91
- db = SQLite3::Database.new "#{@tmpdir}/#{anki21_file_name}", options: {}
92
- @tmp_files << anki21_file_name
93
- db.execute_batch ANKI_SCHEMA_DEFINITION
94
- db.execute CLEAN_COLLECTION_21_RECORD
95
- db.results_as_hash = true
96
- db
97
- end
98
-
99
- def setup_anki2_database_object
100
- anki2_file_name = "collection.anki2"
101
- db = SQLite3::Database.new "#{@tmpdir}/#{anki2_file_name}", options: {}
102
- @tmp_files << anki2_file_name
103
- db.execute_batch ANKI_SCHEMA_DEFINITION
104
- db.execute CLEAN_COLLECTION_2_RECORD
105
- db.close
106
- db
107
- end
108
-
109
- def setup_media
110
- media_file_path = FileUtils.touch("#{@tmpdir}/media")[0]
111
- media_file = File.open(media_file_path, mode: "w")
112
- media_file.write("{}")
113
- media_file.close
114
- @tmp_files << "media"
115
- media_file
116
- end
117
-
118
- def puts_error_and_standard_message(error:)
119
- puts "#{error}\n#{STANDARD_ERROR_MESSAGE}"
120
- end
121
-
122
- public
123
-
124
- ##
125
- # Creates a new object which represents the Anki SQLite3 database file at +path+
126
- #
127
- # Development has focused on ::new so this method is not recommended at this time
128
- def self.open(path:, target_directory: nil, &closure)
129
- pathname = check_file_at_path_is_valid(path: path)
130
- new_apkg_name = "#{File.basename(pathname.to_s, ".apkg")}-#{seconds_since_epoch}"
131
-
132
- @anki_package = if target_directory
133
- new(name: new_apkg_name, directory: target_directory)
134
- else
135
- new(name: new_apkg_name)
136
- end
137
- @anki_package.send :execute_closure_and_zip, @anki_package, &closure if block_given?
138
- @anki_package
139
- end
140
-
141
- class << self
142
- include TimeHelper
143
-
144
- private
145
-
146
- def check_file_at_path_is_valid(path:)
147
- pathname = Pathname.new(path)
148
- raise PATH_ERROR_MESSAGE unless pathname.file? && pathname.extname == ".apkg"
149
-
150
- pathname
151
- end
152
- end
153
-
154
- ##
155
- # Zips the temporary files into the *.apkg package and deletes the temporary files.
156
- def zip
157
- create_zip_file && destroy_temporary_directory
158
- end
159
-
160
- private
161
-
162
- def create_zip_file
163
- Zip::File.open(target_zip_file, create: true) do |zip_file|
164
- @tmp_files.each do |file_name|
165
- zip_file.add(file_name, File.join(@tmpdir, file_name))
166
- end
167
- end
168
- true
169
- end
170
-
171
- def target_zip_file
172
- "#{@directory}/#{@name}.apkg"
173
- end
174
-
175
- def destroy_temporary_directory
176
- @anki21_database.close
177
- FileUtils.rm_rf(@tmpdir)
178
- end
179
-
180
- public
181
-
182
- ##
183
- # Returns true if the database is open
184
- def open?
185
- !closed?
186
- end
187
-
188
- ##
189
- # Returns true if the database is closed
190
- def closed?
191
- @anki21_database.closed?
192
- end
193
- end
194
- end