pirka 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.gitignore +6 -0
- data/.yardopts +1 -0
- data/COPYING.txt +674 -0
- data/ChangeLog.md +4 -0
- data/Gemfile +14 -0
- data/README.md +201 -0
- data/Rakefile +27 -0
- data/app/detect.rb +166 -0
- data/app/highlight.rb +161 -0
- data/app/lib.rb +52 -0
- data/app/subcommand.rb +35 -0
- data/app/update.rb +67 -0
- data/app.rb +74 -0
- data/bin/pirka +17 -0
- data/lib/pirka/config.rb +110 -0
- data/lib/pirka/library.rb +152 -0
- data/lib/pirka/version.rb +22 -0
- data/lib/pirka.rb +1 -0
- data/pirka.gemspec +49 -0
- data/test/fixtures/YWJj.yaml +10 -0
- data/test/helper.rb +18 -0
- data/test/test_library.rb +152 -0
- data/test/test_pirka.rb +12 -0
- metadata +296 -0
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
Pirka
|
2
|
+
=====
|
3
|
+
|
4
|
+
* [Homepage](https://gitlab.com/KitaitiMakoto/pirka)
|
5
|
+
* [Documentation](http://www.rubydoc.info/gems/pirka)
|
6
|
+
* [Email](mailto:KitaitiMakoto at gmail.com)
|
7
|
+
|
8
|
+
Description
|
9
|
+
-----------
|
10
|
+
|
11
|
+
Pirka highlights source code syntax in EPUB books
|
12
|
+
|
13
|
+
Features
|
14
|
+
--------
|
15
|
+
|
16
|
+
* Highlights synatax in EPUB files
|
17
|
+
* Extracts `<code>` elements from EPUB files and asks you which programing language they are, and then uses them to highlight
|
18
|
+
* Downloads shared code and language information from Git repository
|
19
|
+
|
20
|
+
Examples
|
21
|
+
--------
|
22
|
+
|
23
|
+
### Highlighting source code syntax in EPUB books ###
|
24
|
+
|
25
|
+
$ pirka path/to/book.epub
|
26
|
+
|
27
|
+
It's a short cut to:
|
28
|
+
|
29
|
+
$ pirka highlight path/to/book.epub
|
30
|
+
|
31
|
+
### Detecting source code from EPUB books ###
|
32
|
+
|
33
|
+
$ pirka detect path/to/book.epub
|
34
|
+
Detecting code from "Book Title"
|
35
|
+
Library file was saved to:
|
36
|
+
path/to/library.yaml
|
37
|
+
|
38
|
+
`library.yaml` here includes:
|
39
|
+
|
40
|
+
* location of `<code>` element(expressed by [EPUB CFI][] but you don't need to undarstand it.)
|
41
|
+
* `language` field with blank value
|
42
|
+
* file path in EPUB file(zip archive)
|
43
|
+
* source code
|
44
|
+
|
45
|
+
Example:
|
46
|
+
|
47
|
+
epubcfi(/6/64!/4/2/30/2): # location
|
48
|
+
language: # language name. blank at first
|
49
|
+
item: OEBPS/text/p-003-003.xhtml # file path in zip archive
|
50
|
+
code: | # source code
|
51
|
+
f1 = open("|cat", "w")
|
52
|
+
f2 = open("|sed 's/a/b/'", "w")
|
53
|
+
f1.print "Hello\n"
|
54
|
+
f2.print "abc\n"
|
55
|
+
f1.close
|
56
|
+
f2.close
|
57
|
+
|
58
|
+
In Pirka context, the file is called *library*.
|
59
|
+
|
60
|
+
`pirka highlight` command determines programming languages of source code according to this file.
|
61
|
+
Read source code, determine languages, write it at `language` field, remove `code` field, and then
|
62
|
+
you can highlight the EPUB file by `pirka highlight`.
|
63
|
+
|
64
|
+
You also determine languages interactively. Set `-i`(`--interactive`) option:
|
65
|
+
|
66
|
+
$ pirka detect -i path/to/book.epub
|
67
|
+
|
68
|
+
[EPUB CFI]: http://www.idpf.org/epub/linking/cfi/
|
69
|
+
|
70
|
+
### Updating libraries ###
|
71
|
+
|
72
|
+
$ pirka update
|
73
|
+
|
74
|
+
Pirka provides official library files for some EPUB books as Git repository((https://gitlab.com/KitaitiMakoto/pirka-library)[https://gitlab.com/KitaitiMakoto/pirka-library]). `pirka update` command fethes the files from the repository and you benefit from it.
|
75
|
+
|
76
|
+
Additionally, you can host library files by your own and make Pirka recognizes it by configuration file. See later section for that.
|
77
|
+
|
78
|
+
### Listing supported books ###
|
79
|
+
|
80
|
+
$ pirka lib
|
81
|
+
|
82
|
+
`pirka lib` command lists books Pirka can highlight with:
|
83
|
+
|
84
|
+
* Release Identifier(special identifier for EPUB books)
|
85
|
+
* location of library file
|
86
|
+
* title
|
87
|
+
* some other metadata
|
88
|
+
|
89
|
+
### Configuration ###
|
90
|
+
|
91
|
+
Pirka can be configured by environment variables, config file and command-line options.
|
92
|
+
|
93
|
+
#### Environment variables ####
|
94
|
+
|
95
|
+
XDG_DATA_HOME
|
96
|
+
: Affects directory to save library files.
|
97
|
+
: Library files are saved to `$XDG_DATA_HOME/pirka/local`
|
98
|
+
: The directory is used to search library, too.
|
99
|
+
: Default: `$HOME/.local/share`
|
100
|
+
|
101
|
+
XDG_DATA_DIRS
|
102
|
+
: Affects directory to save library files.
|
103
|
+
: You can specify multiple directory by seperating with a colon like `XDG_DATA_DIRS=/dir1:/dir2`.
|
104
|
+
: `/dir1/pirka/local` and `/dir2/pirka/local` are used to search library, for example.
|
105
|
+
: Default: `/usr/local/share:/usr/share`
|
106
|
+
|
107
|
+
XDG_CONFIG_HOME
|
108
|
+
: Affects directory to search and save config file.
|
109
|
+
: `$XDG_CONFIG_DIRS/pirka.yaml` is recognized as config file.
|
110
|
+
: Default: `$HOME/.config`
|
111
|
+
|
112
|
+
XDG_CONFIG_DIRS
|
113
|
+
: Affects directory to search config file.
|
114
|
+
: You can specify multiple directory by seperating with a colon like `XDG_CONFIG_DIRS=/dir1:/dir2`.
|
115
|
+
: `/dir1/pirka.yaml` and `/dir2/pirka.yaml` are searched as config file.
|
116
|
+
: Default: `/etc/xdg`
|
117
|
+
|
118
|
+
#### Config file ####
|
119
|
+
|
120
|
+
Config file is a YAML file. Properties below are recognized:
|
121
|
+
|
122
|
+
data_home
|
123
|
+
: Directory to save and search library files.
|
124
|
+
: Default: `$XDG_CONFIG_HOME/pirka/local`
|
125
|
+
|
126
|
+
additional_directories
|
127
|
+
: Directories to search library files.
|
128
|
+
: Expressed by sequence(array).
|
129
|
+
: Default: `[]`
|
130
|
+
|
131
|
+
library_repositories
|
132
|
+
: Git repository URIs used by `pirka lib` command.
|
133
|
+
: Expressed by sequence(array).
|
134
|
+
: Default: `[]`
|
135
|
+
|
136
|
+
#### Command-line options ####
|
137
|
+
|
138
|
+
You can configure Pirka by `pirka` command's global options:
|
139
|
+
|
140
|
+
`-c`, `--config=FILE`
|
141
|
+
: Path to config file.
|
142
|
+
: Default: /Users/ikeda/.config/pirka.yaml
|
143
|
+
|
144
|
+
`-s`, `--data-home=DIRECTORY`
|
145
|
+
: Same to config file's `data_home` property.
|
146
|
+
|
147
|
+
`-d`, `--directory=DIRECTORY`
|
148
|
+
: Same to config file's `additional_directories` property.
|
149
|
+
: Able to multilpe times.
|
150
|
+
|
151
|
+
You can also see help by
|
152
|
+
|
153
|
+
$ pirka --help
|
154
|
+
Pirka highlights source code syntax in EPUB files
|
155
|
+
|
156
|
+
Usage: pirka [global options] [<command>] [options]
|
157
|
+
|
158
|
+
Global options:
|
159
|
+
-c, --config=FILE Config file. Defaults to /Users/ikeda/.config/pirka.yaml
|
160
|
+
-s, --data-home=DIRECTORY Directory to *SAVE* library data
|
161
|
+
-d, --directory=DIRECTORY Directory to *SEARCH* library data.
|
162
|
+
Specify multiple times to add multiple directories.
|
163
|
+
|
164
|
+
Commands:
|
165
|
+
highlight Highlights source code in EPUB file
|
166
|
+
detect Detects source code from EPUB file and generate library file
|
167
|
+
update Update library files by remote files
|
168
|
+
lib Show library infomation
|
169
|
+
If command is ommitted, highlight is used with no option
|
170
|
+
|
171
|
+
Requirements
|
172
|
+
------------
|
173
|
+
|
174
|
+
* Ruby 2.2 or later
|
175
|
+
* C compiler to compile [Nokogiri][] gem
|
176
|
+
|
177
|
+
[Nokogiri]: http://www.nokogiri.org/
|
178
|
+
|
179
|
+
Install
|
180
|
+
-------
|
181
|
+
|
182
|
+
$ gem install pirka
|
183
|
+
|
184
|
+
### Make faster ###
|
185
|
+
|
186
|
+
By default, Pirka uses [archive-zip][] gem, a pure Ruby implementation, for zip archive but you can make command execution faster by using [Zip/Ruby][] gem, a C implementation. Just install Zip/Ruby:
|
187
|
+
|
188
|
+
$ gem install zipruby
|
189
|
+
|
190
|
+
Pirka, actually internally-used [EPUB Parser][], tries to load Zip/Ruby and use it if available.
|
191
|
+
|
192
|
+
[archive-zip]: https://github.com/javanthropus/archive-zip
|
193
|
+
[Zip/Ruby]: https://bitbucket.org/winebarrel/zip-ruby/wiki/Home
|
194
|
+
[EPUB Parser]: http://www.rubydoc.info/gems/epub-parser/file/docs/Home.markdown
|
195
|
+
|
196
|
+
Copyright
|
197
|
+
---------
|
198
|
+
|
199
|
+
Copyright (c) 2017 KITAITI Makoto
|
200
|
+
|
201
|
+
See {file:COPYING.txt} for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bundler/setup'
|
7
|
+
rescue LoadError => e
|
8
|
+
abort e.message
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'rake'
|
12
|
+
|
13
|
+
task :default => :test
|
14
|
+
|
15
|
+
require 'rubygems/tasks'
|
16
|
+
Gem::Tasks.new
|
17
|
+
|
18
|
+
require 'rake/testtask'
|
19
|
+
Rake::TestTask.new do |test|
|
20
|
+
test.libs << 'test'
|
21
|
+
test.pattern = 'test/**/test_*.rb'
|
22
|
+
test.verbose = true
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'yard'
|
26
|
+
YARD::Rake::YardocTask.new
|
27
|
+
task :doc => :yard
|
data/app/detect.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "optparse/pathname"
|
3
|
+
require "epub/parser"
|
4
|
+
require "epub/cfi"
|
5
|
+
require "epub/searcher"
|
6
|
+
require "rouge"
|
7
|
+
require "rouge/lexers/fluentd"
|
8
|
+
require "colored"
|
9
|
+
require "pirka/library"
|
10
|
+
require_relative "subcommand"
|
11
|
+
|
12
|
+
module Pirka
|
13
|
+
class App
|
14
|
+
class Detect
|
15
|
+
PROGRAM_NAME = "detect"
|
16
|
+
DESCRIPTION = "Detects source code from EPUB file and generate library file"
|
17
|
+
ARGS = %w[EPUB_FILE]
|
18
|
+
|
19
|
+
include Subcommand
|
20
|
+
|
21
|
+
def initialize(config)
|
22
|
+
super
|
23
|
+
|
24
|
+
@library_path = nil
|
25
|
+
@interactive = false
|
26
|
+
|
27
|
+
@available_lexers = Rouge::Lexer.all.sort_by(&:tag).each_with_object({}).with_index {|(lexer, lexers), index|
|
28
|
+
lexers[(index + 1).to_s] = lexer
|
29
|
+
}
|
30
|
+
initial = nil
|
31
|
+
@lexers_display = @available_lexers.collect {|(index, lexer)|
|
32
|
+
init = lexer.title[0].upcase
|
33
|
+
if initial == init
|
34
|
+
option = ""
|
35
|
+
else
|
36
|
+
option = "\n"
|
37
|
+
initial = init
|
38
|
+
end
|
39
|
+
option << "#{index})".bold << " " << lexer.title
|
40
|
+
option << "(#{lexer.aliases.join(', ')})" unless lexer.aliases.empty?
|
41
|
+
option
|
42
|
+
}.join(" ")
|
43
|
+
@commands = ["s) skip", "q) quit", "c) show code", "o) show options"].join(" ")
|
44
|
+
@commands = {
|
45
|
+
"s" => "skip",
|
46
|
+
"q" => "quit",
|
47
|
+
"c" => "show code",
|
48
|
+
"o" => "show options"
|
49
|
+
}.collect {|(key, command)|
|
50
|
+
"#{key})".bold << " " << command
|
51
|
+
}.join(" ")
|
52
|
+
end
|
53
|
+
|
54
|
+
def run(argv)
|
55
|
+
parse_options! argv
|
56
|
+
|
57
|
+
epub_path = argv.shift
|
58
|
+
raise ArgumentError, 'Specify EPUB file' unless epub_path
|
59
|
+
|
60
|
+
begin
|
61
|
+
# @todo Make this optional
|
62
|
+
require 'epub/maker/ocf/physical_container/zipruby'
|
63
|
+
EPUB::OCF::PhysicalContainer.adapter = :Zipruby
|
64
|
+
rescue LoadError
|
65
|
+
end
|
66
|
+
epub = EPUB::Parser.parse(epub_path)
|
67
|
+
$stderr.puts "Detecting code from \"#{epub.title}\""
|
68
|
+
|
69
|
+
codelist = {}
|
70
|
+
library = Library.new
|
71
|
+
library.metadata["Release Identifier"] = epub.release_identifier
|
72
|
+
library.metadata["title"] = epub.title
|
73
|
+
catch do |quit|
|
74
|
+
EPUB::Searcher.search_element(epub, css: 'code').each do |result|
|
75
|
+
item = result[:itemref].item
|
76
|
+
if @interactive
|
77
|
+
catch do |skip|
|
78
|
+
show_item item
|
79
|
+
show_code result[:element]
|
80
|
+
show_options
|
81
|
+
show_commands
|
82
|
+
i = ask
|
83
|
+
|
84
|
+
while true
|
85
|
+
case i
|
86
|
+
when "s"
|
87
|
+
throw skip
|
88
|
+
when "q"
|
89
|
+
throw quit
|
90
|
+
when "c"
|
91
|
+
show_item item
|
92
|
+
show_code(result[:element])
|
93
|
+
show_options
|
94
|
+
show_commands
|
95
|
+
i = ask
|
96
|
+
when "o"
|
97
|
+
show_options
|
98
|
+
show_commands
|
99
|
+
i = ask
|
100
|
+
else
|
101
|
+
lexer = @available_lexers[i]
|
102
|
+
unless lexer
|
103
|
+
i = ask
|
104
|
+
next
|
105
|
+
end
|
106
|
+
library.codelist[result[:location]] = {"language" => lexer.tag}
|
107
|
+
break
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
else
|
112
|
+
library.codelist[result[:location]] = ({
|
113
|
+
"language" => nil,
|
114
|
+
"item" => result[:itemref].item.entry_name,
|
115
|
+
"code" => result[:element].content
|
116
|
+
})
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
path = library.save(@library_path)
|
121
|
+
$stderr.puts "Library file was saved to:"
|
122
|
+
$stdout.puts path
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def parse_options!(argv)
|
129
|
+
super do |opt|
|
130
|
+
opt.separator ""
|
131
|
+
opt.on "-i", "--interactive" do
|
132
|
+
@interactive = true
|
133
|
+
end
|
134
|
+
opt.on "-o", "--output=FILE", "File to save library data", Pathname do |path|
|
135
|
+
@library_path = path
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def show_item(item)
|
141
|
+
$stderr.puts
|
142
|
+
$stderr.puts item.entry_name
|
143
|
+
end
|
144
|
+
|
145
|
+
def show_code(code)
|
146
|
+
$stderr.puts
|
147
|
+
$stderr.puts code.content
|
148
|
+
$stderr.puts
|
149
|
+
end
|
150
|
+
|
151
|
+
def show_options
|
152
|
+
$stderr.puts @lexers_display
|
153
|
+
end
|
154
|
+
|
155
|
+
def show_commands
|
156
|
+
$stderr.puts
|
157
|
+
$stderr.puts @commands
|
158
|
+
end
|
159
|
+
|
160
|
+
def ask
|
161
|
+
$stderr.print "Which language? "
|
162
|
+
$stdin.gets.chomp
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
data/app/highlight.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "optparse"
|
3
|
+
require "optparse/pathname"
|
4
|
+
require "epub/parser"
|
5
|
+
require "epub/maker"
|
6
|
+
require "rouge"
|
7
|
+
require "rouge/lexers/fluentd"
|
8
|
+
require "pirka/library"
|
9
|
+
require_relative "subcommand"
|
10
|
+
|
11
|
+
module Pirka
|
12
|
+
class App
|
13
|
+
class Highlight
|
14
|
+
PROGRAM_NAME = "highlight"
|
15
|
+
DESCRIPTION = "Highlights source code in EPUB file"
|
16
|
+
ARGS = %w[EPUB_FILE]
|
17
|
+
|
18
|
+
include Subcommand
|
19
|
+
|
20
|
+
DUMMY_ORIGIN = Addressable::URI.parse("file:///")
|
21
|
+
CSS_PATH = "pirka/style.css" # @todo Avoid conflict with existing item by other than Pirka
|
22
|
+
CSS_CLASS_NAME = "pirka"
|
23
|
+
SCOPE = "code.#{CSS_CLASS_NAME}"
|
24
|
+
THEME = "github"
|
25
|
+
|
26
|
+
def initialize(config)
|
27
|
+
super
|
28
|
+
@library_path = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# @todo Handle multiple renditions
|
32
|
+
def run(argv)
|
33
|
+
parse_options! argv
|
34
|
+
|
35
|
+
epub_path = argv.shift
|
36
|
+
raise ArgumentError, 'Specify EPUB file' unless epub_path
|
37
|
+
|
38
|
+
begin
|
39
|
+
# @todo Make this optional
|
40
|
+
require 'epub/maker/ocf/physical_container/zipruby'
|
41
|
+
EPUB::OCF::PhysicalContainer.adapter = :Zipruby
|
42
|
+
rescue LoadError
|
43
|
+
end
|
44
|
+
epub = EPUB::Parser.parse(epub_path)
|
45
|
+
library = find_library(epub.unique_identifier, epub.modified)
|
46
|
+
raise RuntimeError, "Cannot find code list #{Library.filename(epub.release_identifier)} for #{epub.release_identifier}(#{epub_path}) in any directory of #{Library.directories.join(", ")}" unless library
|
47
|
+
|
48
|
+
css_item = add_css_file(epub)
|
49
|
+
need_save = highlight_contents(epub, css_item, library)
|
50
|
+
need_save << css_item
|
51
|
+
need_save.uniq!
|
52
|
+
update_modified_date(epub, Time.now)
|
53
|
+
|
54
|
+
save_file epub, need_save
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param [EPUB::Book, EPUB::Book::Features] epub
|
58
|
+
# @return [EPUB::Publication::Package::Manifest::Item] item indicating added CSS file
|
59
|
+
def add_css_file(epub)
|
60
|
+
rootfile_path = DUMMY_ORIGIN + epub.ocf.container.rootfile.full_path
|
61
|
+
style = Rouge::Theme.find(THEME).new(scope: SCOPE).render
|
62
|
+
|
63
|
+
epub.package.manifest.make_item {|item|
|
64
|
+
item.href = (DUMMY_ORIGIN + CSS_PATH).route_from(rootfile_path)
|
65
|
+
# IMPROVEMENT: Want to call item.entry_name = css_path
|
66
|
+
item.media_type = 'text/css'
|
67
|
+
item.id = CSS_PATH.gsub('/', '-') # @todo Avoid conflict with existing items
|
68
|
+
item.content = style
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
# @todo Do the best when file for release identifier is not find but for unique identifier found
|
73
|
+
def find_library(unique_identifier, modified)
|
74
|
+
@library_path ? Library.load_file(@library_path) :
|
75
|
+
Library.find_by_release_identifier("#{unique_identifier}@#{modified}")
|
76
|
+
end
|
77
|
+
|
78
|
+
# @todo Consider descendant elements of code
|
79
|
+
def highlight_contents(epub, css_item, library)
|
80
|
+
need_save = []
|
81
|
+
|
82
|
+
formatter = Rouge::Formatters::HTML.new
|
83
|
+
|
84
|
+
library.each.reverse_each do |(cfi, data)|
|
85
|
+
lang = data["language"]
|
86
|
+
unless lang
|
87
|
+
warn "Language for #{cfi} is not detected"
|
88
|
+
next
|
89
|
+
end
|
90
|
+
itemref, elem, _ = EPUB::Searcher.search_by_cfi(epub, cfi)
|
91
|
+
item = itemref.item
|
92
|
+
doc = elem.document
|
93
|
+
lexer = Rouge::Lexer.find(lang) || Rouge::Lexer.guess(source: elem.content)
|
94
|
+
unless lexer
|
95
|
+
warn "Cannot find lexer for #{lang}"
|
96
|
+
next
|
97
|
+
end
|
98
|
+
elem.inner_html = formatter.format(lexer.lex(elem.content)) # @todo Consider the case `elem` has descendants
|
99
|
+
|
100
|
+
classes = (elem["class"] || "").split(/\s+/)
|
101
|
+
unless classes.include? CSS_CLASS_NAME
|
102
|
+
classes << CSS_CLASS_NAME
|
103
|
+
elem["class"] = classes.join(" ")
|
104
|
+
end
|
105
|
+
|
106
|
+
link = doc.at('#pirka') # @todo Avoid conflict with existing link
|
107
|
+
unless link
|
108
|
+
item_entry_name = DUMMY_ORIGIN + item.entry_name
|
109
|
+
entry_name = DUMMY_ORIGIN + css_item.entry_name
|
110
|
+
href = entry_name.route_from(item_entry_name)
|
111
|
+
link = Nokogiri::XML::Node.new('link', doc)
|
112
|
+
link['href'] = href
|
113
|
+
link['type'] = 'text/css'
|
114
|
+
link['rel'] = 'stylesheet'
|
115
|
+
link['id'] = 'pirka'
|
116
|
+
head = (doc/'head').first
|
117
|
+
head << link
|
118
|
+
end
|
119
|
+
item.content = doc.to_xml
|
120
|
+
need_save << item
|
121
|
+
end
|
122
|
+
|
123
|
+
need_save
|
124
|
+
end
|
125
|
+
|
126
|
+
def update_modified_date(epub, time = Time.now)
|
127
|
+
modified = epub.modified
|
128
|
+
unless modified
|
129
|
+
modified = EPUB::Publication::Package::Metadata::Meta.new
|
130
|
+
modified.property = 'dcterms:modified'
|
131
|
+
epub.package.metadata.metas << modified
|
132
|
+
end
|
133
|
+
modified.content = time.utc.iso8601
|
134
|
+
|
135
|
+
modified
|
136
|
+
end
|
137
|
+
|
138
|
+
def save_file(epub, need_save)
|
139
|
+
need_save.each do |item|
|
140
|
+
item.save
|
141
|
+
epub.package.manifest << item
|
142
|
+
end
|
143
|
+
epub.package.edit
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
# @todo theme
|
149
|
+
# @todo CSS file path
|
150
|
+
# @todo scope
|
151
|
+
def parse_options!(argv)
|
152
|
+
super do |opt|
|
153
|
+
opt.separator ""
|
154
|
+
opt.on "-l", "--library=FILE", "library file", Pathname do |path|
|
155
|
+
@library_path = path
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
data/app/lib.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "pirka/library"
|
2
|
+
|
3
|
+
module Pirka
|
4
|
+
class App
|
5
|
+
class Lib
|
6
|
+
PROGRAM_NAME = "lib"
|
7
|
+
DESCRIPTION = "Show library infomation"
|
8
|
+
|
9
|
+
include Subcommand
|
10
|
+
|
11
|
+
def run(argv)
|
12
|
+
# show all
|
13
|
+
# show remote repos
|
14
|
+
# show data dirs
|
15
|
+
# show data home
|
16
|
+
# show books
|
17
|
+
# show book metadata
|
18
|
+
|
19
|
+
no_dir_file_length = Library::SUBDIR_LENGTH + Library::EXT.length
|
20
|
+
Library.directories.each do |dir|
|
21
|
+
next unless dir.directory?
|
22
|
+
|
23
|
+
dir.each_child do |child|
|
24
|
+
if child.to_path.length < no_dir_file_length && child.extname != Library::EXT
|
25
|
+
show_info child
|
26
|
+
next
|
27
|
+
end
|
28
|
+
next unless child.directory?
|
29
|
+
next unless child.basename.to_path.length == Library::SUBDIR_LENGTH
|
30
|
+
child.each_child do |lib|
|
31
|
+
next unless lib.extname == Library::EXT
|
32
|
+
next unless lib.file?
|
33
|
+
show_info lib
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def show_info(path)
|
40
|
+
$stdout.puts Library.load_file(path).metadata.to_yaml
|
41
|
+
$stdout.puts "library: #{path}"
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def parse_options!(argv)
|
47
|
+
super do |opt|
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/app/subcommand.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Pirka
|
2
|
+
class App
|
3
|
+
module Subcommand
|
4
|
+
class << self
|
5
|
+
def included(base)
|
6
|
+
APPS[base::PROGRAM_NAME] = base
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# @param [Config]
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# @todo Consider the case the subcommand has no option
|
18
|
+
def parse_options!(argv)
|
19
|
+
parser = OptionParser.new {|opt|
|
20
|
+
usage = "Usage: #{opt.program_name} [options] #{self.class::PROGRAM_NAME}"
|
21
|
+
usage << " " << self.class::ARGS.join(" ") if self::class.const_defined?(:ARGS)
|
22
|
+
|
23
|
+
opt.program_name = "#{opt.program_name} [global options] #{self.class::PROGRAM_NAME}"
|
24
|
+
opt.banner = <<EOB
|
25
|
+
#{self::class::DESCRIPTION}
|
26
|
+
|
27
|
+
#{usage}
|
28
|
+
EOB
|
29
|
+
yield opt if block_given?
|
30
|
+
}
|
31
|
+
parser.order! argv
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|