Skip to content
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

Set title and description in dev #104

Merged
merged 22 commits into from Aug 7, 2017
Merged

Set title and description in dev #104

merged 22 commits into from Aug 7, 2017

Conversation

benbalter
Copy link
Contributor

A follow up to #101, the title and description were only being set in production, making local previewing difficult.

This PR updates the logic to set the title and description in dev by moving the conditional statement.

@benbalter benbalter requested a review from parkr July 27, 2017 14:54
@@ -16,9 +16,8 @@ def munge!
# This is the good stuff.
site.config["github"] = github_namespace

return unless should_add_fallbacks?
add_url_and_baseurl_fallbacks!
add_title_and_description_fallbacks!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should bail early if:

  1. No auth token is present (if they rebuild frequently, they'll start getting 403 Rate Limit Exceeded errors which are confusing)
  2. There is no internet connectivity

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Both are a new feature in themselves, and out of scope for this PR, but 👍 to tackling those in a subsequent pass.

@@ -83,6 +84,10 @@
before(:each) do
Jekyll::GitHubMetadata.client = Jekyll::GitHubMetadata::Client.new({ :access_token => "" })
end
before do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not before(:each)? IIRC before is discouraged because of the random ordering of each test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to this PR, so I'll pull it out (debugging artifact).

@@ -9,7 +9,7 @@
</head>
<body>
<div id="output"></div>
<script src="renderjson.js" type="text/javascript" charset="utf-8"></script>
<script src="{{ "renderjson.js" | absolute_url }}" type="text/javascript" charset="utf-8"></script>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this to ensure the internals that use url and baseurl don't blow up when either is a Proc.

Copy link
Member

@parkr parkr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hooray for Value!

@parkr
Copy link
Member

parkr commented Jul 27, 2017

I'd give this a good whirl with your personal site then ship it.

@benbalter
Copy link
Contributor Author

Also, to memorialize things here publicly, chatting with @parkr, I didn't like the idea that we'd be making API calls for every build, even if the user doesn't use site.title or site.description. By moving the calls to Value wrapped Procs, in theory, a site that has a baseurl set and doesn't call site.title, site.description, site.url or site.github.* should not make an API call.

@parkr
Copy link
Member

parkr commented Jul 27, 2017

Thanks!

If you give the proc an arity of 2, it'll pass you the right repo too! First argument is the Client, second is the Repository 😄

@benbalter
Copy link
Contributor Author

@parkr this could use a second set of 👀 now, but otherwise should be good to go. Per our discussion:

  • Created RepositoryFinder to centralize nwo logic
  • Centralized and memoized site and repository on the GitHubMetadata class
  • Added unit tests for each expected key/value in MetadataDrop
  • Added a test to ensure we're testing all values in MetadataDrop
  • Value now forwards +, and eql? to the value to avoid to_s calls

As a result, when called locally, by default, the plugin should make no external API calls. Only if, for example, site.title is called, and is not defined, or site.github.* is called, will it make an API call.

Copy link
Member

@parkr parkr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Thank you for this. I have just a few suggestions & requests. 😸

@@ -61,9 +62,18 @@ def client
@client ||= Client.new
end

def repository
@repository ||= GitHubMetadata::Repository.new(nwo).tap do |repo|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly what I was looking for, nice 👍

end

def nwo
@nwo ||= GitHubMetadata::RepositoryFinder.nwo
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For anything state-related, it would be nice to use an instance of RepositoryFinder here. It'd be much the same, but the state is thrown away once the nwo is discovered.

@nwo ||= Jekyll::GitHubMetadata::RepositoryFinder.new(site).nwo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we did that, JekyllGitHubMetadata would have to know (or be passed) the site variable (which you seemed to indicate the opposite below).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My struggle is that it's too easy for this data to get all out of sync. I want the behavior that if GitHubMetadata.site changes, that GitHubMetadata.repository changes with it.

module GitHubMetadata
  def self.site
    repository_finder.site
  end

  def self.site=(new_site)
    reset!
    @repository_finder = GitHubMetadata::RepositoryFinder.new(new_site)
  end

  def self.repository
    @repository ||= GitHubMetadata::Repository.new(repository_finder.nwo).tap do |repo|
      Jekyll::GitHubMetadata.log :debug, "Generating for #{repo.nwo}"
    end
  end

  private
  attr_reader :repository_finder
    
  end
end

This enforces a safe top-level environment: when site is set to some other value, it resets everything and creates a new repository_finder instance with the new site.

module Jekyll
module GitHubMetadata
class RepositoryFinder
class << self
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use an instance here. Might be even easier to test that way since the site would just be an instance variable; easier to remember to pass a required parameter to .new than it is to set GitHubMetadata.site before the test executes.

attr_reader :site
extend Forwardable

def_delegators :"Jekyll::GitHubMetadata", :site, :repository
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these need to be public?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

site was already public, but made repo private via 66f4b4a.

@@ -35,13 +36,14 @@ def github_namespace
end

def drop
@drop ||= MetadataDrop.new(site)
@drop ||= MetadataDrop.new
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me feel woozy. I wonder if keeping the site on the global GitHubMetadata is a bad idea? I'm ok with client and repository at that level, but the whole site object scares me.

Copy link
Contributor Author

@benbalter benbalter Aug 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on a better solution? We need site in order to derive the nwo to build repository.

end

# Set `site.url` and `site.baseurl` if unset.
def add_url_and_baseurl_fallbacks!
site.config["url"] ||= repository.url_without_path
site.config["baseurl"] = repository.baseurl if should_set_baseurl?
site.config["url"] ||= Value.new("url", proc { |_c, r| r.url_without_path })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍

@@ -3,6 +3,9 @@
module Jekyll
module GitHubMetadata
class Value
extend Forwardable
def_delegators :render, :+, :to_s, :to_json, :eql?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clever. Can you memoize render so it doesn't render on each call? Or use :value instead of :render.

I'd also like to have a test for each of these – it can be really basic, but I just want to ensure they don't break.

Why #+?

Per Object#hash, if you specify #eql? you must also specify #hash:

Generates an Integer hash value for this object. This function must have the property that a.eql?(b) implies a.hash == b.hash.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memoized via 7027532.

Why #+?

Workaround so we don't need to backport jekyll/jekyll#6253.

Per Object#hash, if you specify #eql? you must also specify #hash:

Done via f0662b0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also like to have a test for each of these – it can be really basic, but I just want to ensure they don't break.

added via 4ea6404

render.to_s
end

def to_json(*)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, we can't just alias this method to #render. to_json must be able to accept a state parameter. We do that in Jekyll::Drops::Drop to great effect. (See how state affects things in DocumentDrop#hash_for_json.)

def to_json(state = nil)
  require "json"
  JSON.generate(value, state)
end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it's def_delegators (plural), I believe it will delegate Value#to_json to calling to_json on the result of #render, meaning it should accept the second argument so long as the result of #render does.

@parkr
Copy link
Member

parkr commented Aug 7, 2017

@jekyllbot: merge +minor

@jekyllbot jekyllbot merged commit 6b53042 into master Aug 7, 2017
@jekyllbot jekyllbot deleted the set-title-in-dev branch August 7, 2017 20:11
jekyllbot added a commit that referenced this pull request Aug 7, 2017
@jekyll jekyll locked and limited conversation to collaborators Apr 28, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants