diff --git a/spec/classes/embedded_converter_spec.cr b/spec/classes/embedded_converter_spec.cr index 4b7ec07..780bc92 100644 --- a/spec/classes/embedded_converter_spec.cr +++ b/spec/classes/embedded_converter_spec.cr @@ -5,6 +5,7 @@ include Nodes describe EmbeddedConverter do context "when the mediaResource has an iframeSrc value" do it "returns an EmbeddedContent node" do + store = GistStore.new paragraph = PostResponse::Paragraph.from_json <<-JSON { "text": "", @@ -25,7 +26,7 @@ describe EmbeddedConverter do } JSON - result = EmbeddedConverter.convert(paragraph) + result = EmbeddedConverter.convert(paragraph, store) result.should eq( EmbeddedContent.new( @@ -40,6 +41,7 @@ describe EmbeddedConverter do context "when the mediaResource has a blank iframeSrc value" do context "and the href is unknown" do it "returns an EmbeddedLink node" do + store = GistStore.new paragraph = PostResponse::Paragraph.from_json <<-JSON { "text": "", @@ -60,7 +62,7 @@ describe EmbeddedConverter do } JSON - result = EmbeddedConverter.convert(paragraph) + result = EmbeddedConverter.convert(paragraph, store) result.should eq(EmbeddedLink.new(href: "https://example.com")) end @@ -68,6 +70,7 @@ describe EmbeddedConverter do context "and the href is gist.github.com" do it "returns an GithubGist node" do + store = GistStore.new paragraph = PostResponse::Paragraph.from_json <<-JSON { "text": "", @@ -88,10 +91,13 @@ describe EmbeddedConverter do } JSON - result = EmbeddedConverter.convert(paragraph) + result = EmbeddedConverter.convert(paragraph, store) result.should eq( - GithubGist.new(href: "https://gist.github.com/user/someid") + GithubGist.new( + href: "https://gist.github.com/user/someid", + gist_store: store + ) ) end end diff --git a/spec/classes/gist_scanner_spec.cr b/spec/classes/gist_scanner_spec.cr new file mode 100644 index 0000000..a5648e6 --- /dev/null +++ b/spec/classes/gist_scanner_spec.cr @@ -0,0 +1,102 @@ +require "../spec_helper" + +describe GistScanner do + it "returns gist ids from paragraphs" do + iframe = PostResponse::IFrame.new( + PostResponse::MediaResource.new( + href: "https://gist.github.com/user/123ABC", + iframeSrc: "", + iframeWidth: 0, + iframeHeight: 0 + ) + ) + paragraphs = [ + PostResponse::Paragraph.new( + text: "Check out this gist:", + type: PostResponse::ParagraphType::P, + markups: [] of PostResponse::Markup, + iframe: nil, + layout: nil, + metadata: nil + ), + PostResponse::Paragraph.new( + text: "", + type: PostResponse::ParagraphType::IFRAME, + markups: [] of PostResponse::Markup, + iframe: iframe, + layout: nil, + metadata: nil + ), + ] + + result = GistScanner.new(paragraphs).scan + + result.should eq(["https://gist.github.com/user/123ABC"]) + end + + it "returns ids without the file parameters" do + iframe = PostResponse::IFrame.new( + PostResponse::MediaResource.new( + href: "https://gist.github.com/user/123ABC?file=example.txt", + iframeSrc: "", + iframeWidth: 0, + iframeHeight: 0 + ) + ) + paragraphs = [ + PostResponse::Paragraph.new( + text: "", + type: PostResponse::ParagraphType::IFRAME, + markups: [] of PostResponse::Markup, + iframe: iframe, + layout: nil, + metadata: nil + ), + ] + + result = GistScanner.new(paragraphs).scan + + result.should eq(["https://gist.github.com/user/123ABC"]) + end + + it "returns a unique list of ids" do + iframe1 = PostResponse::IFrame.new( + PostResponse::MediaResource.new( + href: "https://gist.github.com/user/123ABC?file=example.txt", + iframeSrc: "", + iframeWidth: 0, + iframeHeight: 0 + ) + ) + iframe2 = PostResponse::IFrame.new( + PostResponse::MediaResource.new( + href: "https://gist.github.com/user/123ABC?file=other.txt", + iframeSrc: "", + iframeWidth: 0, + iframeHeight: 0 + ) + ) + paragraphs = [ + PostResponse::Paragraph.new( + text: "", + type: PostResponse::ParagraphType::IFRAME, + markups: [] of PostResponse::Markup, + iframe: iframe1, + layout: nil, + metadata: nil + ), + PostResponse::Paragraph.new( + text: "", + type: PostResponse::ParagraphType::IFRAME, + markups: [] of PostResponse::Markup, + iframe: iframe2, + layout: nil, + metadata: nil + ), + ] + + result = GistScanner.new(paragraphs).scan + + result.should eq(["https://gist.github.com/user/123ABC"]) + end +end diff --git a/spec/classes/gist_store_spec.cr b/spec/classes/gist_store_spec.cr new file mode 100644 index 0000000..182d425 --- /dev/null +++ b/spec/classes/gist_store_spec.cr @@ -0,0 +1,58 @@ +require "../spec_helper" + +describe GistStore do + describe "#store_gist_file" do + describe "adds the gist file to the gist id" do + it "calls the github client" do + store = GistStore.new + file = GistFile.new( + filename: "filename", + content: "content", + raw_url: "raw_url" + ) + + store.store_gist_file("1", file) + + store.store["1"].should eq([file]) + end + end + end + + describe "the gist does not exist in the store" do + it "returns a MissingGistFile" do + missing_file = MissingGistFile.new(id: "1", filename: "filename") + store = GistStore.new + + file = store.get_gist_files(id: "1", filename: "filename") + + file.should eq([missing_file]) + end + end + + describe "when a filename is given" do + it "returns the GistFile for that filename" do + store = GistStore.new + file1 = GistFile.new("one", "", "") + file2 = GistFile.new("two", "", "") + store.store["1"] = [file1, file2] + + gists = store.get_gist_files(id: "1", filename: "one") + + gists.should eq([file1]) + gists.should_not contain([file2]) + end + end + + describe "when a filename is NOT given" do + it "returns all GistFiles" do + store = GistStore.new + file1 = GistFile.new("one", "", "") + file2 = GistFile.new("two", "", "") + store.store["1"] = [file1, file2] + + gists = store.get_gist_files(id: "1", filename: nil) + + gists.should eq([file1, file2]) + end + end +end diff --git a/spec/classes/paragraph_converter_spec.cr b/spec/classes/paragraph_converter_spec.cr index c3e30cb..e66b824 100644 --- a/spec/classes/paragraph_converter_spec.cr +++ b/spec/classes/paragraph_converter_spec.cr @@ -4,6 +4,7 @@ include Nodes describe ParagraphConverter do it "converts a simple structure with no markups" do + gist_store = GistStore.new paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON [ { @@ -18,12 +19,13 @@ describe ParagraphConverter do JSON expected = [Heading3.new(children: [Text.new(content: "Title")] of Child)] - result = ParagraphConverter.new.convert(paragraphs) + result = ParagraphConverter.new.convert(paragraphs, gist_store) result.should eq expected end it "converts a simple structure with a markup" do + gist_store = GistStore.new paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON [ { @@ -54,12 +56,13 @@ describe ParagraphConverter do ] of Child), ] - result = ParagraphConverter.new.convert(paragraphs) + result = ParagraphConverter.new.convert(paragraphs, gist_store) result.should eq expected end it "groups <ul> list items into one list" do + gist_store = GistStore.new paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON [ { @@ -96,12 +99,13 @@ describe ParagraphConverter do Paragraph.new(children: [Text.new(content: "Not a list item")] of Child), ] - result = ParagraphConverter.new.convert(paragraphs) + result = ParagraphConverter.new.convert(paragraphs, gist_store) result.should eq expected end it "groups <ol> list items into one list" do + gist_store = GistStore.new paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON [ { @@ -138,12 +142,13 @@ describe ParagraphConverter do Paragraph.new(children: [Text.new(content: "Not a list item")] of Child), ] - result = ParagraphConverter.new.convert(paragraphs) + result = ParagraphConverter.new.convert(paragraphs, gist_store) result.should eq expected end it "converts an IMG to a Figure" do + gist_store = GistStore.new paragraph = PostResponse::Paragraph.from_json <<-JSON { "text": "Image by someuser", @@ -182,12 +187,13 @@ describe ParagraphConverter do ] of Child), ] - result = ParagraphConverter.new.convert([paragraph]) + result = ParagraphConverter.new.convert([paragraph], gist_store) result.should eq expected end it "converts all the tags" do + gist_store = GistStore.new paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON [ { @@ -333,7 +339,7 @@ describe ParagraphConverter do ] of Child), ] - result = ParagraphConverter.new.convert(paragraphs) + result = ParagraphConverter.new.convert(paragraphs, gist_store) result.should eq expected end diff --git a/spec/classes/rate_limited_gist_store_spec.cr b/spec/classes/rate_limited_gist_store_spec.cr new file mode 100644 index 0000000..a4a3327 --- /dev/null +++ b/spec/classes/rate_limited_gist_store_spec.cr @@ -0,0 +1,23 @@ +require "../spec_helper" + +describe RateLimitedGistStore do + describe "when a filename is given" do + it "returns a RateLimitedGistFile for that filename" do + store = RateLimitedGistStore.new + + gists = store.get_gist_files(id: "1", filename: "one") + + gists.should eq([RateLimitedGistFile.new(id: "1", filename: "one")]) + end + end + + describe "when a filename is NOT given" do + it "returns a single RateLimitedGistFile" do + store = RateLimitedGistStore.new + + gists = store.get_gist_files(id: "1", filename: nil) + + gists.should eq([RateLimitedGistFile.new(id: "1", filename: nil)]) + end + end +end diff --git a/spec/components/page_content_spec.cr b/spec/components/page_content_spec.cr index 7b40351..bdcd9ed 100644 --- a/spec/components/page_content_spec.cr +++ b/spec/components/page_content_spec.cr @@ -146,19 +146,33 @@ describe PageContent do end it "renders a GitHub Gist" do + store = GistStore.new + gist_file = GistFile.new( + filename: "example", + content: "content", + raw_url: "https://gist.githubusercontent.com/user/1/raw/abc/example" + ) + store.store["1"] = [gist_file] page = Page.new( title: "Title", author: user_anchor_factory, created_at: Time.local, nodes: [ - GithubGist.new(href: "https://gist.github.com/user/some_id"), + GithubGist.new(href: "https://gist.github.com/user/1", gist_store: store), ] of Child ) html = PageContent.new(page: page).render_to_string html.should eq stripped_html <<-HTML - <script src="https://gist.github.com/user/some_id.js"></script> + <p> + <code> + <a href="https://gist.github.com/user/1#file-example">example</a> + </code> + </p> + <pre class="gist"> + <code>content</code> + </pre> HTML end diff --git a/spec/models/gist_file_spec.cr b/spec/models/gist_file_spec.cr new file mode 100644 index 0000000..380adcd --- /dev/null +++ b/spec/models/gist_file_spec.cr @@ -0,0 +1,34 @@ +require "../spec_helper" + +describe GistFile do + it "is parsed from json" do + json = <<-JSON + { + "filename": "example.txt", + "raw_url": "https://gist.githubusercontent.com/user/1D/raw/FFF/example.txt", + "content": "content" + } + JSON + + gist_file = GistFile.from_json(json) + + gist_file.filename.should eq("example.txt") + gist_file.content.should eq("content") + gist_file.raw_url.should eq("https://gist.githubusercontent.com/user/1D/raw/FFF/example.txt") + end + + it "returns an href for the gist's webpage" do + json = <<-JSON + { + "filename": "example.txt", + "raw_url": "https://gist.githubusercontent.com/user/1D/raw/FFF/example.txt", + "content": "content" + } + JSON + gist_file = GistFile.from_json(json) + + href = gist_file.href + + href.should eq("https://gist.github.com/user/1D#file-example-txt") + end +end diff --git a/spec/models/gist_params_spec.cr b/spec/models/gist_params_spec.cr new file mode 100644 index 0000000..df711be --- /dev/null +++ b/spec/models/gist_params_spec.cr @@ -0,0 +1,33 @@ +require "../spec_helper" + +describe GistParams do + it "extracts params from the gist url" do + url = "https://gist.github.com/user/1D?file=example.txt" + + params = GistParams.extract_from_url(url) + + params.id.should eq("1D") + params.filename.should eq("example.txt") + end + + describe "when no file param exists" do + it "does not extract a filename" do + url = "https://gist.github.com/user/1D" + + params = GistParams.extract_from_url(url) + + params.id.should eq("1D") + params.filename.should be_nil + end + end + + describe "when the URL is not a gist URL" do + it "raises a MissingGistId exeption" do + url = "https://example.com" + + expect_raises(GistParams::MissingGistId, message: "https://example.com") do + GistParams.extract_from_url(url) + end + end + end +end diff --git a/src/classes/embedded_converter.cr b/src/classes/embedded_converter.cr index 6848bfc..925e54f 100644 --- a/src/classes/embedded_converter.cr +++ b/src/classes/embedded_converter.cr @@ -1,15 +1,22 @@ class EmbeddedConverter include Nodes - GIST_HOST = "https://gist.github.com" + GIST_HOST_AND_SCHEME = "https://#{GIST_HOST}" getter paragraph : PostResponse::Paragraph + getter gist_store : GistStore | RateLimitedGistStore - def self.convert(paragraph : PostResponse::Paragraph) : Embedded | Empty - new(paragraph).convert + def self.convert( + paragraph : PostResponse::Paragraph, + gist_store : GistStore | RateLimitedGistStore + ) : Embedded | Empty + new(paragraph, gist_store).convert end - def initialize(@paragraph : PostResponse::Paragraph) + def initialize( + @paragraph : PostResponse::Paragraph, + @gist_store : GistStore | RateLimitedGistStore + ) end def convert : Embedded | Empty @@ -33,8 +40,8 @@ class EmbeddedConverter end private def custom_embed(media : PostResponse::MediaResource) : Embedded - if media.href.starts_with?(GIST_HOST) - GithubGist.new(href: media.href) + if media.href.starts_with?(GIST_HOST_AND_SCHEME) + GithubGist.new(href: media.href, gist_store: gist_store) else EmbeddedLink.new(href: media.href) end diff --git a/src/classes/gist_scanner.cr b/src/classes/gist_scanner.cr new file mode 100644 index 0000000..9fd6852 --- /dev/null +++ b/src/classes/gist_scanner.cr @@ -0,0 +1,28 @@ +class GistScanner + GIST_HOST_AND_SCHEME = "https://#{GIST_HOST}" + + getter paragraphs : Array(PostResponse::Paragraph) + + def initialize(@paragraphs : Array(PostResponse::Paragraph)) + end + + def scan + maybe_urls = paragraphs.compact_map do |paragraph| + Monads::Try(PostResponse::IFrame).new(->{ paragraph.iframe }) + .to_maybe + .fmap(->(iframe : PostResponse::IFrame) { iframe.mediaResource }) + .fmap(->(media : PostResponse::MediaResource) { media.href }) + .value_or(nil) + end + maybe_urls + .select { |url| url.starts_with?(GIST_HOST_AND_SCHEME) } + .map { |url| url_without_params(url) } + .uniq + end + + def url_without_params(url) + uri = URI.parse(url) + uri.query = nil + uri.to_s + end +end diff --git a/src/classes/gist_store.cr b/src/classes/gist_store.cr new file mode 100644 index 0000000..9fd148a --- /dev/null +++ b/src/classes/gist_store.cr @@ -0,0 +1,45 @@ +alias GistFiles = Array(GistFile) +alias GistHash = Hash(String, GistFiles) + +class GistStore + property store : GistHash + + def initialize(@store : GistHash = {} of String => GistFiles) + end + + def store_gist_file(id : String, file : GistFile) + store[id] ||= [] of GistFile + store[id] << file + end + + def get_gist_files(id : String, filename : String?) : Array(GistFile) | Array(MissingGistFile) + files = store[id]? + missing_file = MissingGistFile.new(id: id, filename: filename) + if files + if filename + find_gist_file(files, filename, missing_file) + else + files + end + else + return [missing_file] + end + end + + private def find_gist_file( + files : Array(GistFile), + filename : String, + missing_file : MissingGistFile + ) : Array(GistFile) | Array(MissingGistFile) + gist_file = files.find { |file| file.filename == filename } + if gist_file + [gist_file] + else + [missing_file] + end + end + + private def client_class + GithubClient + end +end diff --git a/src/classes/page_converter.cr b/src/classes/page_converter.cr index 70f932f..a277f96 100644 --- a/src/classes/page_converter.cr +++ b/src/classes/page_converter.cr @@ -3,11 +3,12 @@ class PageConverter title, content = title_and_content(data) author = data.post.creator created_at = Time.unix_ms(data.post.createdAt) + gist_store = gist_store(content) Page.new( title: title, author: author, created_at: Time.unix_ms(data.post.createdAt), - nodes: ParagraphConverter.new.convert(content) + nodes: ParagraphConverter.new.convert(content, gist_store) ) end @@ -17,4 +18,20 @@ class PageConverter non_content_paragraphs = paragraphs.reject { |para| para.text == title } {title, non_content_paragraphs} end + + private def gist_store(paragraphs) : GistStore | RateLimitedGistStore + store = GistStore.new + gist_urls = GistScanner.new(paragraphs).scan + gist_responses = gist_urls.map do |url| + params = GistParams.extract_from_url(url) + response = GithubClient.get_gist_response(params.id) + if response.is_a?(GithubClient::RateLimitedResponse) + return RateLimitedGistStore.new + end + JSON.parse(response.data.body)["files"].as_h.values.map do |json_any| + store.store_gist_file(params.id, GistFile.from_json(json_any.to_json)) + end + end + store + end end diff --git a/src/classes/paragraph_converter.cr b/src/classes/paragraph_converter.cr index d62185f..00a76f4 100644 --- a/src/classes/paragraph_converter.cr +++ b/src/classes/paragraph_converter.cr @@ -1,7 +1,10 @@ class ParagraphConverter include Nodes - def convert(paragraphs : Array(PostResponse::Paragraph)) : Array(Child) + def convert( + paragraphs : Array(PostResponse::Paragraph), + gist_store : GistStore | RateLimitedGistStore + ) : Array(Child) if paragraphs.first?.nil? return [Empty.new] of Child else @@ -24,7 +27,7 @@ class ParagraphConverter node = Heading3.new(children: children) when PostResponse::ParagraphType::IFRAME paragraph = paragraphs.shift - node = EmbeddedConverter.convert(paragraph) + node = EmbeddedConverter.convert(paragraph, gist_store) when PostResponse::ParagraphType::IMG paragraph = paragraphs.shift node = convert_img(paragraph) @@ -60,7 +63,7 @@ class ParagraphConverter node = Empty.new end - [node, convert(paragraphs)].flatten.reject(&.empty?) + [node, convert(paragraphs, gist_store)].flatten.reject(&.empty?) end end diff --git a/src/classes/rate_limited_gist_store.cr b/src/classes/rate_limited_gist_store.cr new file mode 100644 index 0000000..d5a2516 --- /dev/null +++ b/src/classes/rate_limited_gist_store.cr @@ -0,0 +1,5 @@ +class RateLimitedGistStore + def get_gist_files(id : String, filename : String?) + [RateLimitedGistFile.new(id: id, filename: filename)] + end +end diff --git a/src/clients/github_client.cr b/src/clients/github_client.cr new file mode 100644 index 0000000..b6a5610 --- /dev/null +++ b/src/clients/github_client.cr @@ -0,0 +1,37 @@ +class GithubClient + class SuccessfulResponse + getter data : HTTP::Client::Response + + def initialize(@data : HTTP::Client::Response) + end + end + + class RateLimitedResponse + end + + def self.get_gist_response(id : String) : SuccessfulResponse | RateLimitedResponse + new.get_gist_response(id) + end + + def get_gist_response(id : String) : SuccessfulResponse | RateLimitedResponse + client = HTTP::Client.new("api.github.com", tls: true) + if username && password + client.basic_auth(username, password) + end + response = client.get("/gists/#{id}") + if response.status == HTTP::Status::FORBIDDEN && + response.headers["X-RateLimit-Remaining"] == "0" + RateLimitedResponse.new + else + SuccessfulResponse.new(response) + end + end + + private def username + ENV["GITHUB_USERNAME"]? + end + + private def password + ENV["GITHUB_PERSONAL_ACCESS_TOKEN"]? + end +end diff --git a/src/components/page_content.cr b/src/components/page_content.cr index 7ffb41f..2849bbc 100644 --- a/src/components/page_content.cr +++ b/src/components/page_content.cr @@ -77,8 +77,19 @@ class PageContent < BaseComponent end end - def render_child(child : GithubGist) - script src: child.src + def render_child(gist : GithubGist) + gist.files.map { |gist_file| render_child(gist_file) } + end + + def render_child(gist_file : GistFile | MissingGistFile | RateLimitedGistFile) + para do + code do + a gist_file.filename, href: gist_file.href + end + end + pre class: "gist" do + code gist_file.content + end end def render_child(node : Heading1) diff --git a/src/constants.cr b/src/constants.cr index a136d90..f750574 100644 --- a/src/constants.cr +++ b/src/constants.cr @@ -1,2 +1,4 @@ # https://stackoverflow.com/questions/2669690/ JSON_HIJACK_STRING = "])}while(1);</x>" + +GIST_HOST = "gist.github.com" diff --git a/src/models/gist_file.cr b/src/models/gist_file.cr new file mode 100644 index 0000000..18bced1 --- /dev/null +++ b/src/models/gist_file.cr @@ -0,0 +1,89 @@ +class GistFile + include JSON::Serializable + + getter filename : String + getter content : String + getter raw_url : String + + def initialize(@filename : String, @content : String, @raw_url : String) + end + + def href + uri = URI.parse(raw_url) + uri.host = GIST_HOST + path_and_file_anchor = path_and_file_anchor(uri) + uri.path = path_and_file_anchor.path + uri.fragment = path_and_file_anchor.file_anchor + uri.to_s + end + + private def path_and_file_anchor(uri : URI) + path_parts = uri.path.split("/") + PathAndFileAnchor.new( + path: [path_parts[1], path_parts[2]].join("/"), + filename: path_parts[-1] + ) + end + + class PathAndFileAnchor + getter file_anchor : String + getter path : String + + def initialize(@path : String, filename : String) + @file_anchor = "file-" + filename.tr(" ", "-").tr(".", "-") + end + end +end + +class MissingGistFile + GIST_HOST_AND_SCHEME = "https://#{GIST_HOST}" + + def initialize(@id : String, @filename : String?) + end + + def content + <<-TEXT + Gist file missing. + Click on filename to go to gist. + TEXT + end + + def href + GIST_HOST_AND_SCHEME + "/#{@id}" + end + + def filename + @filename || "Unknown filename" + end + + def ==(other : MissingGistFile) + other.filename == filename && other.href == href + end +end + +class RateLimitedGistFile + GIST_HOST_AND_SCHEME = "https://#{GIST_HOST}" + + def initialize(@id : String, @filename : String?) + end + + def content + <<-TEXT + Can't fetch gist. + GitHub rate limit reached. + Click on filename to go to gist. + TEXT + end + + def href + GIST_HOST_AND_SCHEME + "/#{@id}" + end + + def filename + @filename || "Unknown filename" + end + + def ==(other : RateLimitedGistFile) + other.filename == filename && other.href == href + end +end diff --git a/src/models/gist_params.cr b/src/models/gist_params.cr new file mode 100644 index 0000000..c8d5dfe --- /dev/null +++ b/src/models/gist_params.cr @@ -0,0 +1,30 @@ +class GistParams + class MissingGistId < Exception + end + + GIST_ID_REGEX = /[a-f\d]+$/i + + getter id : String + getter filename : String? + + def self.extract_from_url(href : String) + uri = URI.parse(href) + maybe_id = Monads::Try(Regex::MatchData) + .new(->{ uri.path.match(GIST_ID_REGEX) }) + .to_maybe + .fmap(->(matches : Regex::MatchData) { matches[0] }) + case maybe_id + in Monads::Just + id = maybe_id.value! + in Monads::Nothing, Monads::Maybe + raise MissingGistId.new(href) + end + + filename = uri.query_params["file"]? + + new(id: id, filename: filename) + end + + def initialize(@id : String, @filename : String?) + end +end diff --git a/src/models/nodes.cr b/src/models/nodes.cr index 49fee91..0ddce68 100644 --- a/src/models/nodes.cr +++ b/src/models/nodes.cr @@ -217,15 +217,21 @@ module Nodes end class GithubGist - def initialize(@href : String) + getter gist_store : GistStore | RateLimitedGistStore + + def initialize(@href : String, @gist_store : GistStore | RateLimitedGistStore) end - def src - "#{@href}.js" + def files : Array(GistFile) | Array(MissingGistFile) | Array(RateLimitedGistFile) + gist_store.get_gist_files(params.id, params.filename) + end + + private def params + GistParams.extract_from_url(@href) end def ==(other : GithubGist) - other.src == src + other.gist_store == gist_store end def empty? diff --git a/src/models/post_response.cr b/src/models/post_response.cr index ff960d0..aedf898 100644 --- a/src/models/post_response.cr +++ b/src/models/post_response.cr @@ -38,6 +38,16 @@ class PostResponse property iframe : IFrame? property layout : String? property metadata : Metadata? + + def initialize( + @text : String?, + @type : ParagraphType, + @markups : Array(Markup), + @iframe : IFrame?, + @layout : String?, + @metadata : Metadata? + ) + end end enum ParagraphType @@ -80,6 +90,9 @@ class PostResponse class IFrame < Base property mediaResource : MediaResource + + def initialize(@mediaResource : MediaResource) + end end class MediaResource < Base @@ -87,6 +100,14 @@ class PostResponse property iframeSrc : String property iframeWidth : Int32 property iframeHeight : Int32 + + def initialize( + @href : String, + @iframeSrc : String, + @iframeWidth : Int32, + @iframeHeight : Int32 + ) + end end class Metadata < Base diff --git a/src/version.cr b/src/version.cr index efa2c88..c22052a 100644 --- a/src/version.cr +++ b/src/version.cr @@ -1,3 +1,3 @@ module Scribe - VERSION = "2022-01-08" + VERSION = "2022-01-23" end