Skip to content

Commit

Permalink
Merge pull request #356 from hanami/feature/10version
Browse files Browse the repository at this point in the history
Separate guides for each version
  • Loading branch information
davydovanton committed Aug 2, 2017
2 parents 0e93ec5 + dc325ff commit 4858bc2
Show file tree
Hide file tree
Showing 77 changed files with 9,662 additions and 8 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ gem 'middleman-syntax', '~> 2.0'
gem 'middleman-deploy', '~> 1.0'
gem 'middleman-search_engine_sitemap', '~> 1.3'
gem 'middleman-search'
gem 'middleman-breadcrumbs'
gem 'redcarpet', '~> 3.2'
gem 'httparty'

Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ GEM
addressable (~> 2.3.5)
middleman-core (~> 3.2)
tzinfo (>= 0.3.0)
middleman-breadcrumbs (0.3.3)
middleman (>= 3.3.5)
middleman-core (3.4.1)
activesupport (~> 4.1)
bundler (~> 1.1)
Expand Down Expand Up @@ -168,6 +170,7 @@ DEPENDENCIES
httparty
middleman (~> 3.3)
middleman-blog (~> 3.5)
middleman-breadcrumbs
middleman-deploy (~> 1.0)
middleman-livereload (~> 3.1)
middleman-search
Expand Down
40 changes: 34 additions & 6 deletions config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
}
end

activate :breadcrumbs

###
# Compass
###
Expand Down Expand Up @@ -122,15 +124,16 @@ def article_image_url(article)
GUIDES_ROOT = 'source/guides'.freeze
GUIDES_EDIT_URL = 'https://github.com/hanami/hanami.github.io/edit/build/'.freeze

def guide_title(item)
def guide_title(item, version = nil)
item.title || item.path.split('-').map(&:capitalize).join(' ')
end

def guide_url(category, page)
File.join('/guides', category.path, page.path)
def guide_url(category, page, version = nil)
path = version ? "/guides/#{version}" : '/guides'
File.join(path, category.path, page.path)
end

def guide_pager(current_page, guides)
def guide_pager(current_page, guides, version = nil)
current_url = current_page.url.tr('/', '')
flat_guides = guides.categories.flat_map { |category|
category.pages.map { |page|
Expand All @@ -147,14 +150,14 @@ def guide_pager(current_page, guides)
links = []
prev_guide = flat_guides[current_guide_index - 1]
if 0 < current_guide_index && prev_guide
prev_url = guide_url(prev_guide.category, prev_guide.page)
prev_url = guide_url(prev_guide.category, prev_guide.page, version)
prev_title = "#{guide_title(prev_guide.category)} - #{guide_title(prev_guide.page)}"
links << %(<div class="pull-left">Prev: <a href="#{prev_url}">#{prev_title}</a></div>)
end

next_guide = flat_guides[current_guide_index + 1]
if next_guide
next_url = guide_url(next_guide.category, next_guide.page)
next_url = guide_url(next_guide.category, next_guide.page, version)
next_title = "#{guide_title(next_guide.category)} - #{guide_title(next_guide.page)}"
links << %(<div class="pull-right">Next: <a href="#{next_url}">#{next_title}</a></div>)
end
Expand Down Expand Up @@ -201,6 +204,31 @@ def guides_edit_article(source)
%(<a href="#{ url }" target="_blank"><span class="icon icon-pencil" id="edit-guides-article" title="Edit this article"></span></a>)
end

ROOT_GUIDE_PAGE_REGEXP = %r(\A/guides/([\d\.]+/)?\z)

def breadcrumbs(page, **payload)
metadata = page.metadata
version = metadata[:page]['version']
version_text = (version) ? "/ #{link_to(version, "/guides/#{version}")} " : nil
page_title = metadata[:page]['title'].split(' - ').last

category = data.guides.categories.select do |c|
c['pages'].map { |p| p['path'] }.include?(page.url.split('/').last)
end.first

if page.url[ROOT_GUIDE_PAGE_REGEXP]
full_page_title = ''
else
full_page_title = "/ #{category_title(category)} / #{page_title}"
end

"#{link_to('Guides', '/guides')} #{version_text} #{full_page_title}"
end

def category_title(category)
category['title'] || category['path'].split('-').map(&:capitalize).join(' ')
end

#
# UTILS
#
Expand Down
7 changes: 7 additions & 0 deletions data/guides.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,10 @@ categories:
title: v0.9.0
- path: v100
title: v1.0.0
- path: /
title: Old Guides
pages:
- path: /
title: 'Head'
- path: '1.0'
title: v1.0
134 changes: 134 additions & 0 deletions source/guides/1.0/actions/basic-usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
---
title: Guides - Actions Basic Usage
version: 1.0
---

# Basic Usage

## Requests Handling

In the [previous section](/guides/1.0/actions/overview), we generated an action. Now let's use it.

First, we check our routes:

```ruby
# apps/web/config/routes.rb
get '/dashboard', to: 'dashboard#index'
```

### View Rendering

Then we edit the corresponding template:

```erb
# apps/web/templates/dashboard/index.html.erb
<h1>Dashboard</h1>
```

Here is how Hanami handles an incoming request:

1. The router creates a new instance of `Web::Controllers::Dashboard::Index` and invokes `#call`.
2. The application creates a new instance of `Web::Views::Dashboard::Index` and invokes `#render`.
3. The application returns the response to the browser.

<p class="convention">
For a given action named <code>Web::Controllers::Dashboard::Index</code>, a corresponding view MUST be present: <code>Web::Views::Dashboard::Index</code>.
</p>

If we visit `/dashboard` we should see `<h1>Dashboard</h1>` in our browser.

### Bypass Rendering

By default an action takes care of the HTTP status code and response header, but not of the body of the response.
As seen above, it delegates the corresponding view to render and set this value.

Sometimes we want to bypass this process.
For instance we want to return a simple body like `OK`.
To involve a view in this case is a waste of CPU cycles.

If we set the body of the response from an action, **our application will ignore the view**.

```ruby
# apps/web/controllers/dashboard/index.rb
module Web::Controllers::Dashboard
class Index
include Web::Action

def call(params)
self.body = 'OK'
end
end
end
```

Here how Hanami handles an incoming request in this case:

1. The router creates a new instance of `Web::Controllers::Dashboard::Index` and invokes `#call`.
2. The application detects that a body is already set and doesn't instantiate the view.
3. The application returns the response to the browser.

If we visit `/dashboard` again, now we should see `OK`.

<p class="convention">
If the response body was already set by an action, the rendering process is bypassed.
</p>

With direct body assignment, **we can safely delete the corresponding view and template**.

## Initialization

Actions are instantiated for us by Hanami at the runtime: for each incoming request, we'll automatically get a new instance.
Because actions are objects, **we can take control on their initialization** and eventually [_inject_ our dependencies](http://en.wikipedia.org/wiki/Dependency_injection).
This is a really useful technique for unit testing our actions.

```ruby
# apps/web/controllers/dashboard/index.rb
module Web::Controllers::Dashboard
class Index
include Web::Action

def initialize(greeting: Greeting.new)
@greeting = greeting
end

def call(params)
self.body = @greeting.message
end
end
end
```

There is a limitation that we should always be kept in mind:

<p class="warning">
Action initializer MUST have an arity of 0.
</p>

The following initializers are valid:

```ruby
# no arguments
def initialize
# ...
end

# default arguments
def initialize(greeting = Greeting.new)
# ...
end

# keyword arguments
def initialize(greeting: Greeting.new)
# ...
end

# options
def initialize(options = {})
# ...
end

# splat arguments
def initialize(*args)
# ...
end
```
Loading

0 comments on commit 4858bc2

Please sign in to comment.