synclenote 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c352d27660c56aff8d5d3b774d1638375ebb74a422e3ed7406357b4e5a3581e
4
- data.tar.gz: '09925a4b803b45996af5b343aee9d6d851dae75369a8d035dc3a4c3e4707ec4c'
3
+ metadata.gz: 6842ad72e5f7f899d1b5d962b8af0db7cae65c99e16693cedd43de396b51c529
4
+ data.tar.gz: 296010bb3a8b526e43a49986314076bb85be2cd9a7c2cade2fd4a50eb6cf361f
5
5
  SHA512:
6
- metadata.gz: 10752a91ecb12fa3357153e636cb00085c9249d32dc20a3634d4742cce7d464879d0db21c45543e6aef52880fa6afcf0ef2366379edc6cdfdfc8b4a6c440a8fd
7
- data.tar.gz: bbcd3faa70e11247052fdc3d56b35d0adf448ebff62977afdca80a2256be1fe6bbf132952dca7bdc6abe353955b7ec8a6f35c35c6752a370489a2e5ffec2b91d
6
+ metadata.gz: b64e8832799ca114404b838d28fb159d4730072041caf405601d372ada55a25816741486cdcc864e89b4ea8c500a7b4de640d7f5bf26d1c01c4abc5a3beddc92
7
+ data.tar.gz: 7f1a3179d818e0fcff4e3174ce66d517d05e87ed8f31447cbaaa6c80e6ef2888501286c315107ca7050e380fb8be94d1ccd8252a749c0897fda393a89d472821
@@ -0,0 +1,68 @@
1
+ name: test
2
+
3
+ on:
4
+ - pull_request
5
+ - push
6
+ - workflow_dispatch
7
+
8
+ jobs:
9
+ test:
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ os:
14
+ - macos
15
+ - ubuntu
16
+ - windows
17
+ ruby_version:
18
+ - 3.3
19
+ - 3.2
20
+ - 3.1
21
+ runs-on: ${{ matrix.os }}-latest
22
+ steps:
23
+ - uses: actions/checkout@v3
24
+ - uses: kenchan0130/actions-system-info@1.2.0
25
+ id: system-info
26
+ - name: Cache rubygems
27
+ uses: actions/cache@v3.2.2
28
+ with:
29
+ path: vendor/bundle
30
+ key: ${{ runner.os }}-${{ steps.system-info.outputs.release }}-rubygems-${{ matrix.ruby_version }}-${{ hashFiles('**/Gemfile') }}-${{ hashFiles('**/*.gemspec') }}
31
+ restore-keys: |
32
+ ${{ runner.os }}-${{ steps.system-info.outputs.release }}-rubygems-${{ matrix.ruby_version }}
33
+ - name: Set up Ruby
34
+ uses: ruby/setup-ruby@v1
35
+ with:
36
+ ruby-version: ${{ matrix.ruby_version }}
37
+ - name: Install dependencies
38
+ shell: bash
39
+ run: |
40
+ set -eux
41
+ gem update --system
42
+ bundle config path vendor/bundle
43
+ bundle install --jobs "${{ steps.system-info.outputs.cpu-core }}" --retry 3
44
+ - name: Run tests
45
+ run: bundle exec rake
46
+ - name: Output versions
47
+ if: always()
48
+ shell: bash
49
+ run: |
50
+ set -eux
51
+ run_if_exist() {
52
+ if test "x$(which $1)" != "x"
53
+ then
54
+ "$@"
55
+ fi
56
+ }
57
+ uname -a
58
+ run_if_exist sw_vers # macos
59
+ run_if_exist lsb_release --all # ubuntu
60
+ ruby --version
61
+ gem --version
62
+ bundle --version
63
+ - name: Output gem versions
64
+ if: always()
65
+ run: bundle list
66
+ - name: Output deb package versions
67
+ if: always() && matrix.os == 'ubuntu'
68
+ run: dpkg -l
data/Rakefile CHANGED
@@ -1,3 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rake/testtask"
2
3
 
3
- task default: %i(build)
4
+ Rake::TestTask.new do |t|
5
+ t.libs << "test"
6
+ t.test_files = FileList["test/**/*_test.rb"]
7
+ end
8
+
9
+ task(default: %i[test build])
@@ -1,5 +1,3 @@
1
- require "synclenote"
2
-
3
1
  require "yaml"
4
2
  require "pathname"
5
3
  require "logger"
@@ -137,18 +135,6 @@ EOS
137
135
 
138
136
  EOS
139
137
 
140
- HEADER = <<EOS.freeze
141
- <?xml version="1.0" encoding="UTF-8"?>
142
- <!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
143
- <en-note>
144
- EOS
145
-
146
- FOOTER = <<EOS.freeze
147
- </en-note>
148
- EOS
149
-
150
- TITLE_IF_EMPTY = "no title"
151
-
152
138
  def load_yaml_path(path)
153
139
  return YAML.safe_load(
154
140
  path.read,
@@ -183,46 +169,8 @@ EOS
183
169
  return 4 # 4 sec for sandbox
184
170
  end
185
171
 
186
- def build_html(markdown_text)
187
- @formatter ||= Redcarpet::Markdown.new(
188
- Redcarpet::Render::HTML.new(
189
- filter_html: true,
190
- hard_wrap: true,
191
- ),
192
- underline: true,
193
- lax_spacing: true,
194
- footnotes: true,
195
- no_intra_emphasis: true,
196
- superscript: true,
197
- strikethrough: true,
198
- tables: true,
199
- space_after_headers: true,
200
- fenced_code_blocks: true,
201
- # autolink: true,
202
- )
203
- html = @formatter.render(markdown_text)
204
- return html
205
- end
206
-
207
- def create_note(note_path, options = {})
208
- title = nil
209
- tags = ["syncle"]
210
- body = nil
211
- note_path.open do |f|
212
- title = f.gets.chomp.sub(/\A#\s*/, "")
213
- if md = /\A(?<tags>(?:\[.*?\])+)(?:\s|\z)/.match(title)
214
- tags += md[:tags].scan(/\[(.*?)\]/).flatten
215
- title = md.post_match
216
- end
217
- body = f.read
218
- end
219
- html = build_html(body)
220
- content = HEADER +
221
- html.gsub(/ class=\".*?\"/, "").gsub(/<(br|hr|img).*?>/, "\\&</\\1>") +
222
- FOOTER
223
- title = TITLE_IF_EMPTY if /\A\s*\z/ === title
224
- o = options.merge(title: title, content: content, tagNames: tags)
225
- return Evernote::EDAM::Type::Note.new(o)
172
+ def create_note(note_path, **options)
173
+ return Synclenote::NoteBuilder.(note_path, **options)
226
174
  end
227
175
 
228
176
  def target_note?(note)
@@ -1,5 +1,3 @@
1
- require "synclenote"
2
-
3
1
  require "ostruct"
4
2
 
5
3
  module Synclenote::Configuration
@@ -0,0 +1,52 @@
1
+ require "nokogiri"
2
+ require "redcarpet"
3
+
4
+ class Synclenote::MarkdownToEnmlBuilder
5
+ HEADER = <<~EOS
6
+ <?xml version="1.0" encoding="UTF-8"?>
7
+ <!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
8
+ <en-note>
9
+ EOS
10
+
11
+ FOOTER = <<~EOS
12
+ </en-note>
13
+ EOS
14
+
15
+ class << self
16
+ def call(markdown_text)
17
+ formatter = Redcarpet::Markdown.new(
18
+ Redcarpet::Render::HTML.new(
19
+ filter_html: true,
20
+ hard_wrap: true,
21
+ ),
22
+ underline: true,
23
+ lax_spacing: true,
24
+ footnotes: true,
25
+ no_intra_emphasis: true,
26
+ superscript: true,
27
+ strikethrough: true,
28
+ tables: true,
29
+ space_after_headers: true,
30
+ fenced_code_blocks: true,
31
+ # autolink: true,
32
+ )
33
+ html = formatter.render(markdown_text)
34
+ root = Nokogiri::HTML::DocumentFragment.parse(html)
35
+
36
+ root.css("*[class]").each do |node|
37
+ node.remove_attribute("class")
38
+ end
39
+
40
+ # '<a href="example.html?foo=bar&baz=quux">'
41
+ # =>
42
+ # '<a href="example.html?foo=bar&amp;baz=quux">'
43
+ treated_html = root.to_html
44
+ content = [
45
+ HEADER,
46
+ treated_html.gsub(/<(br|hr|img).*?>/, "\\&</\\1>"),
47
+ FOOTER,
48
+ ].join
49
+ return content
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,41 @@
1
+ module Synclenote::NoteBuilder
2
+ DEFAULT_TAGS = %w[syncle]
3
+
4
+ TITLE_IF_EMPTY = "no title"
5
+
6
+ class << self
7
+ def call(raw_note, guid: nil)
8
+ lines = raw_note.each_line.lazy
9
+ title, tags_in_raw_note, body_markdown = *parse_lines(lines)
10
+ title = TITLE_IF_EMPTY if /\A\s*\z/ === title
11
+ tags = (DEFAULT_TAGS + tags_in_raw_note).uniq
12
+ enml = Synclenote::MarkdownToEnmlBuilder.(body_markdown)
13
+
14
+ options = {
15
+ title:,
16
+ content: enml,
17
+ tagNames: tags,
18
+ }
19
+ options[:guid] = guid if guid
20
+ return Evernote::EDAM::Type::Note.new(options)
21
+ end
22
+
23
+ private
24
+
25
+ def parse_lines(lines)
26
+ tags = []
27
+ title = lines.first.chomp.sub(/\A#\s*/, "")
28
+ lines = lines.drop(1)
29
+ md = /\A(?<tags>(?:\[.*?\])+)(?:\s|\z)/.match(title)
30
+ if md
31
+ tags = md[:tags].scan(/\[(.*?)\]/).flatten
32
+ title = md.post_match
33
+ end
34
+
35
+ lines = lines.drop_while { |l| /\A\s*\z/ === l }
36
+ body_markdown = lines.to_a.join
37
+
38
+ return [title, tags, body_markdown]
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,3 @@
1
1
  module Synclenote
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/synclenote.rb CHANGED
@@ -1,12 +1,14 @@
1
1
  # This module is a namespace for this gem.
2
2
  module Synclenote
3
3
  DRY_RUN = false
4
- autoload :VERSION, "synclenote/varsion"
5
-
6
- autoload :Command, "synclenote/command"
7
- autoload :Configuration, "synclenote/configuration"
8
4
 
9
5
  def self.configure(version, &block)
10
6
  Configuration.run(version, &block)
11
7
  end
12
8
  end
9
+
10
+ (Pathname(__dir__).glob("**/*.rb") - [Pathname(__FILE__)]).map { |path|
11
+ path.sub_ext("")
12
+ }.sort.each do |path|
13
+ require(path.relative_path_from(__dir__))
14
+ end
data/synclenote.gemspec CHANGED
@@ -24,10 +24,13 @@ Gem::Specification.new do |spec|
24
24
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
25
25
  spec.require_paths = ["lib"]
26
26
 
27
+ spec.add_runtime_dependency "base64" # suppress warnings
27
28
  spec.add_runtime_dependency "evernote_oauth"
29
+ spec.add_runtime_dependency "nokogiri"
28
30
  spec.add_runtime_dependency "redcarpet"
29
31
  spec.add_runtime_dependency "thor"
30
32
  spec.add_development_dependency "bundler"
31
33
  spec.add_development_dependency "debug"
32
34
  spec.add_development_dependency "rake"
35
+ spec.add_development_dependency "test-unit"
33
36
  end
@@ -0,0 +1,58 @@
1
+ require "test_helper"
2
+
3
+ class Synclenote::MarkdownToEnmlBuilderTest < Test::Unit::TestCase
4
+ sub_test_case(".call") do
5
+ data(
6
+ regular_text: {
7
+ markdown_text: <<~EOS,
8
+ body
9
+ EOS
10
+ expected_enml_text: <<~EOS,
11
+ <p>body</p>
12
+ EOS
13
+ },
14
+ fenced_code_blocks: {
15
+ markdown_text: <<~EOS,
16
+ ```ruby
17
+ 1 + 2 * 3
18
+ ```
19
+ EOS
20
+ # remove "class" attribute
21
+ expected_enml_text: <<~EOS,
22
+ <pre><code>1 + 2 * 3
23
+ </code></pre>
24
+ EOS
25
+ },
26
+ hard_wrap: {
27
+ markdown_text: <<~EOS,
28
+ abc
29
+ def
30
+ EOS
31
+ # convert "<br/>" to "<br></br>"
32
+ expected_enml_text: <<~EOS,
33
+ <p>abc<br></br>
34
+ def</p>
35
+ EOS
36
+ },
37
+ hyperlink: {
38
+ markdown_text: <<~EOS,
39
+ [link text](https://example.org/?foo=bar&baz=quux;hoge=fuga#anchor)
40
+ EOS
41
+ # convert "&" to "&amp;"
42
+ expected_enml_text: <<~EOS,
43
+ <p><a href="https://example.org/?foo=bar&amp;baz=quux;hoge=fuga#anchor">link text</a></p>
44
+ EOS
45
+ },
46
+ )
47
+ test("returns ENML String") do |h|
48
+ assert_equal(
49
+ [
50
+ Synclenote::MarkdownToEnmlBuilder::HEADER,
51
+ h[:expected_enml_text],
52
+ Synclenote::MarkdownToEnmlBuilder::FOOTER,
53
+ ].join,
54
+ Synclenote::MarkdownToEnmlBuilder.(h[:markdown_text]),
55
+ )
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,68 @@
1
+ require "test_helper"
2
+
3
+ class Synclenote::NoteBuilderTest < Test::Unit::TestCase
4
+ sub_test_case(".call") do
5
+ data(
6
+ regular: {
7
+ raw_note_text: <<~EOS,
8
+ # title
9
+
10
+ body
11
+ EOS
12
+ expected_title: "title",
13
+ expected_additional_tag_names: [],
14
+ expected_content_body: <<~EOS,
15
+ <p>body</p>
16
+ EOS
17
+ },
18
+ no_title: {
19
+ raw_note_text: <<~EOS,
20
+ # \t
21
+
22
+ body
23
+ EOS
24
+ expected_title: Synclenote::NoteBuilder::TITLE_IF_EMPTY,
25
+ expected_additional_tag_names: [],
26
+ expected_content_body: <<~EOS,
27
+ <p>body</p>
28
+ EOS
29
+ },
30
+ have_tags: {
31
+ raw_note_text: <<~EOS,
32
+ # [foo][bar-baz] title
33
+
34
+ body
35
+ EOS
36
+ expected_title: "title",
37
+ expected_additional_tag_names: %w[foo bar-baz],
38
+ expected_content_body: <<~EOS,
39
+ <p>body</p>
40
+ EOS
41
+ },
42
+ )
43
+ test("returns Note object") do |h|
44
+ Tempfile.create do |f|
45
+ f.write(h[:raw_note_text])
46
+ f.close
47
+ raw_note_path = Pathname(f.path)
48
+ note = Synclenote::NoteBuilder.(raw_note_path)
49
+ assert_equal(h[:expected_title], note.title)
50
+ assert_equal(
51
+ [
52
+ *Synclenote::NoteBuilder::DEFAULT_TAGS,
53
+ *h[:expected_additional_tag_names],
54
+ ].sort,
55
+ note.tagNames.sort,
56
+ )
57
+ assert_equal(
58
+ [
59
+ Synclenote::MarkdownToEnmlBuilder::HEADER,
60
+ h[:expected_content_body],
61
+ Synclenote::MarkdownToEnmlBuilder::FOOTER,
62
+ ].join,
63
+ note.content,
64
+ )
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ require "test/unit"
2
+
3
+ require "synclenote"
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synclenote
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuya.Nishida.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-13 00:00:00.000000000 Z
11
+ date: 2024-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base64
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: evernote_oauth
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +38,20 @@ dependencies:
24
38
  - - ">="
25
39
  - !ruby/object:Gem::Version
26
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: redcarpet
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +122,20 @@ dependencies:
94
122
  - - ">="
95
123
  - !ruby/object:Gem::Version
96
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: test-unit
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
97
139
  description: A synchronization tool for GFM (GitHub Flavored Markdown) files and Evernote.
98
140
  email:
99
141
  - yuya@j96.org
@@ -103,6 +145,7 @@ extensions: []
103
145
  extra_rdoc_files: []
104
146
  files:
105
147
  - ".github/dependabot.yml"
148
+ - ".github/workflows/test.yml"
106
149
  - ".gitignore"
107
150
  - ".travis.yml"
108
151
  - Gemfile
@@ -114,8 +157,13 @@ files:
114
157
  - lib/synclenote.rb
115
158
  - lib/synclenote/command.rb
116
159
  - lib/synclenote/configuration.rb
160
+ - lib/synclenote/markdown_to_enml_builder.rb
161
+ - lib/synclenote/note_builder.rb
117
162
  - lib/synclenote/version.rb
118
163
  - synclenote.gemspec
164
+ - test/lib/synclenote/markdown_to_enml_builder_test.rb
165
+ - test/lib/synclenote/note_builder_test.rb
166
+ - test/test_helper.rb
119
167
  homepage: https://github.com/nishidayuya/synclenote
120
168
  licenses:
121
169
  - X11
@@ -139,4 +187,7 @@ rubygems_version: 3.5.3
139
187
  signing_key:
140
188
  specification_version: 4
141
189
  summary: A synchronization tool for GFM (GitHub Flavored Markdown) files and Evernote.
142
- test_files: []
190
+ test_files:
191
+ - test/lib/synclenote/markdown_to_enml_builder_test.rb
192
+ - test/lib/synclenote/note_builder_test.rb
193
+ - test/test_helper.rb