middleman-extensionless-helper 1.0.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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/Gemfile +18 -0
  4. data/LICENSE.md +21 -0
  5. data/README.md +193 -0
  6. data/Rakefile +14 -0
  7. data/features/another_build_dir.feature +27 -0
  8. data/features/avoid-layout.feature +25 -0
  9. data/features/erb-path.feature +24 -0
  10. data/features/erb.feature +57 -0
  11. data/features/html_erb.feature +20 -0
  12. data/features/no_erb.feature +28 -0
  13. data/features/no_file.feature +18 -0
  14. data/features/no_target.feature +19 -0
  15. data/features/ruby_file.feature +21 -0
  16. data/features/support/env.rb +4 -0
  17. data/fixtures/another-build-dir-app/_BUILD_DIR_REQUIED_ +0 -0
  18. data/fixtures/another-build-dir-app/config.rb +1 -0
  19. data/fixtures/another-build-dir-app/source/target.erb +1 -0
  20. data/fixtures/another-build-dir-app/source/target.txt.erb +1 -0
  21. data/fixtures/avoid-layout-app/config.rb +1 -0
  22. data/fixtures/avoid-layout-app/source/layouts/layout.erb +3 -0
  23. data/fixtures/avoid-layout-app/source/target.erb +1 -0
  24. data/fixtures/avoid-layout-app/source/target.txt.erb +1 -0
  25. data/fixtures/erb-app/config.rb +1 -0
  26. data/fixtures/erb-app/source/.htaccess.erb +1 -0
  27. data/fixtures/erb-app/source/.target.erb +1 -0
  28. data/fixtures/erb-app/source/target.erb +1 -0
  29. data/fixtures/erb-app/source/target.txt.erb +1 -0
  30. data/fixtures/erb-app/source/target_cap.ERB +1 -0
  31. data/fixtures/erb-app/source/target_inner_.erb_.erb +1 -0
  32. data/fixtures/erb-app/source/target_no_tag.erb +1 -0
  33. data/fixtures/erb-app/source/target_no_tag.txt.erb +1 -0
  34. data/fixtures/erb-path-app/config.rb +1 -0
  35. data/fixtures/erb-path-app/source/sub/target.erb +1 -0
  36. data/fixtures/erb-path-app/source/sub/target.txt.erb +1 -0
  37. data/fixtures/html-erb-app/config.rb +1 -0
  38. data/fixtures/html-erb-app/source/target.html.erb +1 -0
  39. data/fixtures/no-erb-app/config.rb +1 -0
  40. data/fixtures/no-erb-app/source/target +1 -0
  41. data/fixtures/no-erb-app/source/target.erb.txt +1 -0
  42. data/fixtures/no-erb-app/source/target.txt +1 -0
  43. data/fixtures/no-file-app/config.rb +1 -0
  44. data/fixtures/no-file-app/source/target.erb +1 -0
  45. data/fixtures/no-target-app/config.rb +1 -0
  46. data/fixtures/no-target-app/source/target.erb +1 -0
  47. data/fixtures/no-target-app/source/target.txt.erb +1 -0
  48. data/fixtures/ruby-file-app/config.rb +1 -0
  49. data/fixtures/ruby-file-app/source/target.rb +4 -0
  50. data/fixtures/ruby-file-app/source/target.txt +4 -0
  51. data/lib/middleman-extensionless-helper.rb +6 -0
  52. data/lib/middleman-extensionless-helper/extension.rb +169 -0
  53. data/lib/middleman-extensionless-helper/version.rb +5 -0
  54. data/lib/middleman_extension.rb +1 -0
  55. data/middleman-extensionless-helper.gemspec +24 -0
  56. metadata +156 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 51a62b069c13d681ab55c192751795e908b390ec
4
+ data.tar.gz: 2f52076a6deefec06181a889bfc74abfba942794
5
+ SHA512:
6
+ metadata.gz: bc1199811b6942ffc9a27146cf91bd2c1335b8e57e523a291acb1fdd526d0c1bd5d672314338442e3c683e4346009db6a86f2edb5351cacd78cb23afe3fa24e0
7
+ data.tar.gz: 3f058f37d2bbf499d24f33ecfe9cc103fe51234b78e2ce149781aad403eab9aac5aae087ce3576b039d3c78fbdd7d1ebb67f38a04a23b549193b63bb76def6a0
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ # Ignore bundler lock file
2
+ Gemfile.lock
3
+
4
+ # Ignore pkg folder
5
+ pkg
6
+
7
+ .bundle
8
+ tmp
9
+ vendor
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in middleman-extensionless-helper.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem "nokogiri", '1.6.3'
8
+
9
+ gem 'rake'
10
+ gem 'rdoc'
11
+ gem 'yard'
12
+ end
13
+
14
+ group :test do
15
+ gem 'cucumber'
16
+ gem 'aruba'
17
+ gem 'rspec'
18
+ end
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ (c) 2016 AT-AT
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,193 @@
1
+ # Middleman-Extensionless-Helper
2
+
3
+ middleman-extensionless-helper is a Middleman(only for v3) extension to remove a file extension which is attached to extension-less files by the "automatically adding content extensions" feature in a build process.
4
+
5
+ Currently, this extension only works for ERb, and works for files that are specified in the option of this extension.
6
+
7
+ ### What is the "automatically adding content extensions"?
8
+
9
+ Let's say, Middleman builds the following file
10
+
11
+ ```
12
+ source/foo.erb
13
+ ```
14
+
15
+ to
16
+
17
+ ```
18
+ build/foo.html.erb
19
+ ```
20
+
21
+ This is the "automatically adding content extensions" feature.
22
+ But in some cases, we want to avoid this feature.
23
+ This extension renames it to
24
+
25
+ ```
26
+ build/foo
27
+ ```
28
+
29
+ However, Middleman builds following files
30
+
31
+ ```
32
+ source/
33
+ .erb
34
+ .foo.erb
35
+ bar.txt.erb
36
+ baz.quux.erb
37
+ ```
38
+
39
+ to
40
+
41
+ ```
42
+ build/
43
+ # ".erb" and ".foo.erb" does not be built,
44
+ # because Middleman only builds ".htaccess" and ".htpasswd" on the dot file.
45
+
46
+ # Middleman does not attach extension to a file which has some extension.
47
+ bar.txt
48
+ baz.quux
49
+ ```
50
+
51
+ So, this extension never handle those files.
52
+
53
+ ### Why only for v3?
54
+
55
+ Because Middleman-v4 does not have the "automatically adding content extensions" feature.
56
+ See [this issue](https://github.com/middleman/middleman/issues/1211).
57
+
58
+ ### Why only for ERb?
59
+
60
+ Because others are not general-purpose format like as ERb, IMO there is no need to handle them.
61
+
62
+ ## Installation
63
+
64
+ Add the following line to the Gemfile of your Middleman project:
65
+
66
+ ```ruby
67
+ gem "middleman-extensionless-helper"
68
+ ```
69
+
70
+ Then as usual, run:
71
+
72
+ ```sh
73
+ bundle install
74
+ ```
75
+
76
+ ## Usage
77
+
78
+ To activate and configure this extension, add the following configuration block to Middleman's config.rb:
79
+
80
+ ```ruby
81
+ activate :extensionless_helper do |f|
82
+ # The "target" option has been initialized with a empty Array.
83
+ f.target << 'foo.erb' # assumed to be placed in "source/foo.erb"
84
+ # It is possible to change whole the value.
85
+ f.target = ['foo.erb', 'bar/baz.erb'] # assumed to be placed in "source/foo.erb", "source/bar/baz.erb"
86
+ end
87
+ ```
88
+
89
+ | Option | Description
90
+ | ---------- | ------------
91
+ | target | An array with target files placed in a `source` directory.<br>Relative path from the `source` directory is acceptable.
92
+
93
+ ## Build Messages
94
+
95
+ This extension displays some messages in a build process as below.
96
+
97
+ Let's say, beginning state is:
98
+
99
+ ```
100
+ build/
101
+ (empty)
102
+ source/
103
+ foo.erb
104
+ ```
105
+
106
+ Run build, then messages are:
107
+
108
+ ```
109
+ create build/foo.html <-- Middleman says
110
+ EH:rename build/foo.html => build/foo <-- This extension says
111
+ ```
112
+
113
+ Then, state is:
114
+
115
+ ```
116
+ build/
117
+ foo
118
+ source/
119
+ foo.erb
120
+ ```
121
+
122
+ Just build again without any change, then messages are:
123
+
124
+ ```
125
+ identical build/foo.html <-- Middleman says
126
+ EH:rename build/foo.html => build/foo (identical) <-- This extension says
127
+ ```
128
+
129
+ Then, state is:
130
+
131
+ ```
132
+ build/
133
+ foo
134
+ source/
135
+ foo.erb
136
+ ```
137
+
138
+ Change `foo.erb` and build, then messages are:
139
+
140
+ ```
141
+ update build/foo.html <-- Middleman says
142
+ EH:rename build/foo.html => build/foo (update) <-- This extension says
143
+ ```
144
+
145
+ Then, state is:
146
+
147
+ ```
148
+ build/
149
+ foo
150
+ source/
151
+ foo.erb
152
+ ```
153
+
154
+ Remove `foo.erb` and build, then messages are:
155
+
156
+ ```
157
+ remove build/foo.html <-- Middleman says
158
+ EH:remove build/foo <-- This extension says
159
+ ```
160
+
161
+ Then, state is:
162
+
163
+ ```
164
+ build/
165
+ (empty)
166
+ source/
167
+ (empty)
168
+ ```
169
+
170
+ Just build again, then message is:
171
+
172
+ ```
173
+ EH:no-target build/foo <-- This extension says
174
+ ```
175
+
176
+ ## Development
177
+
178
+ Personal references:
179
+ * [Middleman-v3 - Document/custom extensions](https://github.com/middleman/middleman-guides/blob/v3/source/localizable/advanced/custom_extensions.jp.html.markdown)
180
+ * [Middleman-v3 - steps](https://github.com/middleman/middleman/tree/v3-stable/middleman-core/lib/middleman-core/step_definitions)
181
+ * [Cucumber-ruby](https://github.com/cucumber/cucumber-ruby)
182
+ * [Aruba](https://github.com/cucumber/aruba)
183
+ * [Thor - Actions](http://www.rubydoc.info/github/wycats/thor/Thor/Actions)
184
+ * [Thor - Shell/Basic](http://www.rubydoc.info/github/wycats/thor/Thor/Shell/Basic)
185
+
186
+ ## TODO
187
+
188
+ * Add unit test.
189
+ * Consider test for displaying message.
190
+
191
+ ## License
192
+
193
+ (c) 2016 AT-AT. MIT Licensed, see [LICENSE](LICENSE.md) for details.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'cucumber/rake/task'
5
+
6
+ Cucumber::Rake::Task.new(:cucumber, 'Run features that should pass') do |t|
7
+ t.cucumber_opts = "--format progress --color --tags ~@wip --strict"
8
+ end
9
+
10
+ require 'rake/clean'
11
+
12
+ task test: ['cucumber']
13
+
14
+ task default: :test
@@ -0,0 +1,27 @@
1
+ Feature: Handle ERb files placed in the another(not default) build directory.
2
+
3
+ Scenario: Build ERb file
4
+ Given a fixture app "another-build-dir-app"
5
+ And a file named "config.rb" with:
6
+ """
7
+ activate :extensionless_helper do |f|
8
+ f.target = [
9
+ 'target.erb',
10
+ 'target.txt.erb',
11
+ ]
12
+ end
13
+ set :test_msg, 'CONVERTED'
14
+ configure :build do
15
+ set :build_dir, %Q!#{config[:build_dir]}_another!
16
+ end
17
+ """
18
+ And a successfully built app at "another-build-dir-app"
19
+ When I cd to "build_another"
20
+
21
+ Then a file named "target.html" should not exist
22
+ Then a file named "target" should exist
23
+ Then the file "target" should contain "CONVERTED"
24
+
25
+ Then a file named "target.txt" should exist
26
+ Then the file "target.txt" should contain "CONVERTED"
27
+
@@ -0,0 +1,25 @@
1
+ Feature: Avoid applying a layout.
2
+
3
+ Scenario: There's a layout file
4
+ Given a fixture app "avoid-layout-app"
5
+ And a file named "config.rb" with:
6
+ """
7
+ activate :extensionless_helper do |f|
8
+ f.target = [
9
+ 'target.erb',
10
+ 'target.txt.erb',
11
+ ]
12
+ end
13
+ set :test_msg, 'CONVERTED'
14
+ """
15
+ And a successfully built app at "avoid-layout-app"
16
+ When I cd to "build"
17
+
18
+ Then a file named "target" should exist
19
+ Then the file "target" should contain "CONVERTED"
20
+ Then the file "target" should not contain "html"
21
+
22
+ Then a file named "target.txt" should exist
23
+ Then the file "target.txt" should contain "CONVERTED"
24
+ Then the file "target.txt" should not contain "html"
25
+
@@ -0,0 +1,24 @@
1
+ Feature: Handle ERb files designated with a relative path.
2
+
3
+ Scenario: Build ERb file
4
+ Given a fixture app "erb-path-app"
5
+ And a file named "config.rb" with:
6
+ """
7
+ activate :extensionless_helper do |f|
8
+ f.target = [
9
+ 'sub/target.erb',
10
+ 'sub/target.txt.erb',
11
+ ]
12
+ end
13
+ set :test_msg, 'CONVERTED'
14
+ """
15
+ And a successfully built app at "erb-path-app"
16
+ When I cd to "build"
17
+
18
+ Then a file named "sub/target.html" should not exist
19
+ Then a file named "sub/target" should exist
20
+ Then the file "sub/target" should contain "CONVERTED"
21
+
22
+ Then a file named "sub/target.txt" should exist
23
+ Then the file "sub/target.txt" should contain "CONVERTED"
24
+
@@ -0,0 +1,57 @@
1
+ Feature: Handle ERb files.
2
+
3
+ Scenario: Build ERb file
4
+ Given a fixture app "erb-app"
5
+ And a file named "config.rb" with:
6
+ """
7
+ activate :extensionless_helper do |f|
8
+ f.target = [
9
+ # Handle in the following cases.
10
+ '.htaccess.erb',
11
+ 'target.erb',
12
+ 'target_no_tag.erb',
13
+
14
+ # Except, because dot file other than ".htaccess" and ".htpasswd" do not be built.
15
+ '.target.erb',
16
+
17
+ # Except, because file has two(src, dest) extensions.
18
+ 'target.txt.erb',
19
+ 'target_inner_.erb_.erb',
20
+ 'target_no_tag.txt.erb',
21
+
22
+ # Except, because capitalized extension do NOT produce auto-adding-ext.
23
+ 'target_cap.ERB',
24
+ ]
25
+ end
26
+ set :test_msg, 'CONVERTED'
27
+ """
28
+ And a successfully built app at "erb-app"
29
+ When I cd to "build"
30
+
31
+ Then a file named ".htaccess" should exist
32
+ Then the file ".htaccess" should contain "CONVERTED"
33
+
34
+ Then a file named "target.html" should not exist
35
+ Then a file named "target" should exist
36
+ Then the file "target" should contain "CONVERTED"
37
+
38
+ Then a file named "target_no_tag" should exist
39
+ Then the file "target_no_tag" should not contain "CONVERTED"
40
+
41
+
42
+ Then a file named ".target" should not exist
43
+
44
+
45
+ Then a file named "target.txt" should exist
46
+ Then the file "target.txt" should contain "CONVERTED"
47
+
48
+ Then a file named "target_inner_.erb_" should exist
49
+ Then the file "target_inner_.erb_" should contain "CONVERTED"
50
+
51
+ Then a file named "target_no_tag.txt" should exist
52
+ Then the file "target_no_tag.txt" should not contain "CONVERTED"
53
+
54
+
55
+ Then a file named "target_cap" should exist
56
+ Then the file "target_cap" should contain "CONVERTED"
57
+
@@ -0,0 +1,20 @@
1
+ Feature: Handle a ERb file for HTML.
2
+ In this case, this extension does nothing.
3
+
4
+ Scenario: Build HTML from ERb file
5
+ Given a fixture app "html-erb-app"
6
+ And a file named "config.rb" with:
7
+ """
8
+ activate :extensionless_helper do |f|
9
+ f.target = [
10
+ 'target.html.erb',
11
+ ]
12
+ end
13
+ set :test_msg, 'CONVERTED'
14
+ """
15
+ And a successfully built app at "html-erb-app"
16
+ When I cd to "build"
17
+
18
+ Then a file named "target.html" should exist
19
+ Then the file "target.html" should contain "CONVERTED"
20
+
@@ -0,0 +1,28 @@
1
+ Feature: Handle no ERb file.
2
+ In this case, this extension does nothing.
3
+
4
+ Scenario: Build no ERb file
5
+ Given a fixture app "no-erb-app"
6
+ And a file named "config.rb" with:
7
+ """
8
+ activate :extensionless_helper do |f|
9
+ f.target = [
10
+ 'target',
11
+ 'target.txt',
12
+ 'target.erb.txt',
13
+ ]
14
+ end
15
+ set :test_msg, 'CONVERTED'
16
+ """
17
+ And a successfully built app at "no-erb-app"
18
+ When I cd to "build"
19
+
20
+ Then a file named "target" should exist
21
+ Then the file "target" should not contain "CONVERTED"
22
+
23
+ Then a file named "target.txt" should exist
24
+ Then the file "target.txt" should not contain "CONVERTED"
25
+
26
+ Then a file named "target.erb.txt" should exist
27
+ Then the file "target.erb.txt" should not contain "CONVERTED"
28
+
@@ -0,0 +1,18 @@
1
+ Feature: Handle a non-existent file.
2
+ In this case, this extension does nothing.
3
+
4
+ Scenario: Designated file does not exist
5
+ Given a fixture app "no-file-app"
6
+ And a file named "config.rb" with:
7
+ """
8
+ activate :extensionless_helper do |f|
9
+ f.target = [
10
+ 'this_file_does_not_exist.erb',
11
+ ]
12
+ end
13
+ set :test_msg, 'CONVERTED'
14
+ """
15
+ And a successfully built app at "no-file-app"
16
+ When I cd to "build"
17
+ Then a file named "this_file_does_not_exist" should not exist
18
+
@@ -0,0 +1,19 @@
1
+ Feature: Handle no target.
2
+ In this case, this extension does nothing.
3
+
4
+ Scenario: No target is designated
5
+ Given a fixture app "no-target-app"
6
+ And a file named "config.rb" with:
7
+ """
8
+ activate :extensionless_helper
9
+ set :test_msg, 'CONVERTED'
10
+ """
11
+ And a successfully built app at "no-target-app"
12
+ When I cd to "build"
13
+
14
+ Then a file named "target.html" should exist
15
+ Then the file "target.html" should contain "CONVERTED"
16
+
17
+ Then a file named "target.txt" should exist
18
+ Then the file "target.txt" should contain "CONVERTED"
19
+
@@ -0,0 +1,21 @@
1
+ # Change below tag(@wip) to anything else when invoke this test.
2
+ @wip
3
+ Feature: Handle a ruby file.
4
+ This feature(test) is not for the extension, but leave for a examination.
5
+ The Problem:
6
+ MM builds a file by rendering with a template engine.
7
+ If content extension that is acceptable for available template engines is not attached, MM uses ERb.
8
+ However, ERb removes a magic comment of Ruby in ANY file type, like .rb, .txt, .py(!), etc.
9
+ This problem prevents to place ruby script that should not be changed in the source directory. 8-(
10
+
11
+ Scenario: A Ruby file is placed in the source directory
12
+ Given a fixture app "ruby-file-app"
13
+ And a successfully built app at "ruby-file-app"
14
+ When I cd to "build"
15
+
16
+ Then a file named "target.rb" should exist
17
+ Then the file "target.rb" should contain "# coding: utf-8"
18
+
19
+ Then a file named "target.txt" should exist
20
+ Then the file "target.txt" should contain "# coding: utf-8"
21
+
@@ -0,0 +1,4 @@
1
+ PROJECT_ROOT_PATH = File.dirname(File.dirname(File.dirname(__FILE__)))
2
+ require 'middleman-core'
3
+ require 'middleman-core/step_definitions'
4
+ require File.join(PROJECT_ROOT_PATH, 'lib', 'middleman-extensionless-helper')
@@ -0,0 +1 @@
1
+ activate :extensionless_helper
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ activate :extensionless_helper
@@ -0,0 +1,3 @@
1
+ <html>
2
+ <%= yield %>
3
+ </html>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ activate :extensionless_helper
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ This file should not be changed.
@@ -0,0 +1 @@
1
+ This file should not be changed.
@@ -0,0 +1 @@
1
+ activate :extensionless_helper
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ activate :extensionless_helper
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ activate :extensionless_helper
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ activate :extensionless_helper
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ activate :extensionless_helper
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ <%= config[:test_msg] %>
@@ -0,0 +1 @@
1
+ activate :extensionless_helper
@@ -0,0 +1,4 @@
1
+ # coding: utf-8
2
+
3
+ puts 'Hello, Ruby!'
4
+
@@ -0,0 +1,4 @@
1
+ # coding: utf-8
2
+
3
+ puts 'Hello, Ruby!'
4
+
@@ -0,0 +1,6 @@
1
+ require 'middleman-core'
2
+
3
+ ::Middleman::Extensions.register(:extensionless_helper) do
4
+ require 'middleman-extensionless-helper/extension'
5
+ ::Middleman::ExtensionLessHelper
6
+ end
@@ -0,0 +1,169 @@
1
+ module Middleman
2
+ class ExtensionLessHelper < Extension
3
+ option :target, [], 'Target files/paths from the source directory'
4
+
5
+ EXTENSION_MAP = {
6
+ '.erb' => '.html'
7
+ }
8
+
9
+
10
+ def initialize(app, options_hash={}, &block)
11
+ super
12
+
13
+ require 'digest/sha2'
14
+ require 'fileutils'
15
+ require 'ostruct'
16
+
17
+ @target = create_target(options.target)
18
+ end
19
+
20
+
21
+ #
22
+ # Hooks
23
+ #
24
+
25
+ public
26
+
27
+ def after_configuration
28
+
29
+ # Avoid applying a layout to target files.
30
+ # #page requires a URL having a absolute path from the root that is not the source directory
31
+ # but the web site. Besides, because of it's the URL, a file name in it must be the same as MM
32
+ # names in a build process. Hence the URL looks like "/foo.html"(the original file is "foo").
33
+ @target.each do |target|
34
+ app.page File.join('', target.build), :layout => false
35
+ end
36
+
37
+ end
38
+
39
+ def before_build(builder)
40
+
41
+ # Rename target files in the build directory for avoiding a "create" message by MM.
42
+ # e.g. build/foo -> build/foo.html
43
+ # Because target files are renamed by this extension in a previous build process, MM cannot
44
+ # find them and assumes that they are newly created and displays a "create" message.
45
+ # So, restore a name of target files to one which MM names in a build process.
46
+ @target.each do |target|
47
+ rename_build_file(target.expect, target.build)
48
+ end
49
+
50
+ # SHOULD do after above the process, because a build path in a target object is referred.
51
+ inject_target_state
52
+
53
+ end
54
+
55
+ def after_build(builder)
56
+
57
+ # Rename target files in the build directory as we expect.
58
+ # e.g. build/foo.html -> build/foo
59
+ @target.each do |target|
60
+ rename_build_file(target.build, target.expect)
61
+
62
+ # SHOULD do after above the process, because a build path in a target object is referred.
63
+ present_status(builder, target)
64
+
65
+ end
66
+
67
+ end
68
+
69
+
70
+ #
71
+ # Internals
72
+ #
73
+
74
+ private
75
+
76
+ def convert_source_path(source)
77
+ # This isn't a smart way, but shouldn't use #split|Regexp because there are some "edge" cases.
78
+
79
+ template_exts = EXTENSION_MAP.keys
80
+
81
+ first_ext = File.extname(source).downcase
82
+ return {} unless template_exts.include?(first_ext)
83
+
84
+ expected_path = source.sub(/#{Regexp.quote(first_ext)}$/i, '')
85
+ return {} if File.extname(expected_path) != ''
86
+
87
+ base_name = File.basename expected_path
88
+ return {} if base_name.start_with?('.') && !base_name.match(/^\.ht(?:access|passwd)$/)
89
+
90
+ build_ext = EXTENSION_MAP[first_ext]
91
+ {build: (expected_path + build_ext), expect: expected_path}
92
+ end
93
+
94
+ def create_target(target)
95
+
96
+ # SHOULD NOT check an existence of file in here, because files in a source directory are
97
+ # changed, created and removed until starting a build process.
98
+ [target].flatten.inject([]) do |stack, path|
99
+ paths = convert_source_path(path)
100
+ (stack << OpenStruct.new(paths.merge(original: path))) if !paths.empty?
101
+ stack
102
+ end
103
+
104
+ end
105
+
106
+ def digest_of(path)
107
+ Digest::SHA256.file(path).hexdigest
108
+ end
109
+
110
+ def inject_target_state
111
+ state_skel = {created: false, removed: false, active: true, digest: ''}
112
+
113
+ @target.each do |target|
114
+ path_in_source = path_of target.original, :source
115
+ path_in_build = path_of target.build, :build
116
+ in_source = File.file? path_in_source
117
+ in_build = File.file? path_in_build
118
+ state = OpenStruct.new state_skel.dup
119
+
120
+ case true
121
+ when in_source && in_build then # no-op # File is updated or identical.
122
+ when in_source && !in_build then state.created = true # File is created.
123
+ when !in_source && in_build then state.removed = true # File is removed.
124
+ else state.active = false # No file.
125
+ end
126
+
127
+ state.digest = digest_of(path_in_build) if in_build
128
+ target.state = state
129
+ end
130
+ end
131
+
132
+ def path_of(path_crumb, type, absolute = true)
133
+
134
+ # SHOULD get path to the build|source directory at any time of need, because the configuration
135
+ # value of :build_dir|:source can be updated anytime.
136
+ id = type.to_sym == :build ? :build_dir : :source
137
+ path = File.join(app.config[id], path_crumb)
138
+ absolute ? File.expand_path(path) : path
139
+ end
140
+
141
+ def present_status(builder, target)
142
+ build_path = ->(path){ path_of path, :build, false }
143
+ message = "#{build_path.call target.build} => #{build_path.call target.expect}"
144
+
145
+ status, message, color = \
146
+ case true
147
+ when target.state.created
148
+ ['rename', "#{message} (create)", :green]
149
+ when target.state.removed
150
+ ['remove', "#{build_path.call target.expect}", :red]
151
+ when target.state.active
152
+ digest_of(path_of(target.expect, :build)) == target.state.digest \
153
+ ? ['rename', "#{message} (identical)", :blue] \
154
+ : ['rename', "#{message} (update)", :yellow]
155
+ else
156
+ ['no-target', path_of(target.original, :source, false), :magenta]
157
+ end
158
+
159
+ builder.say_status "EH:#{status}", message, color
160
+ end
161
+
162
+ def rename_build_file(from, to)
163
+ src, dest = [path_of(from, :build), path_of(to, :build)]
164
+ FileUtils.mv(src, dest) if File.file?(src) && !File.exist?(dest)
165
+ end
166
+
167
+ end
168
+ end
169
+
@@ -0,0 +1,5 @@
1
+ module Middleman
2
+ class ExtensionlessHelper
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ require 'middleman-extensionless-helper'
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "middleman-extensionless-helper/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "middleman-extensionless-helper"
7
+ s.version = Middleman::ExtensionlessHelper::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["AT-AT"]
10
+ s.email = ["dec.alpha21264@gmail.com"]
11
+ s.homepage = "https://github.com/AT-AT/middleman-extensionless-helper"
12
+ s.summary = %q{A Middleman extension to remove an automatically added content extension}
13
+ s.description = %q{A Middleman extension to remove an automatically added content extension}
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features,fixtures}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ # The version of middleman-core your extension depends on
20
+ s.add_runtime_dependency("middleman-core", ["~> 3.4.1"])
21
+
22
+ # Additional dependencies
23
+ # None.
24
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: middleman-extensionless-helper
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - AT-AT
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: middleman-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.4.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.4.1
27
+ description: A Middleman extension to remove an automatically added content extension
28
+ email:
29
+ - dec.alpha21264@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - Gemfile
36
+ - LICENSE.md
37
+ - README.md
38
+ - Rakefile
39
+ - features/another_build_dir.feature
40
+ - features/avoid-layout.feature
41
+ - features/erb-path.feature
42
+ - features/erb.feature
43
+ - features/html_erb.feature
44
+ - features/no_erb.feature
45
+ - features/no_file.feature
46
+ - features/no_target.feature
47
+ - features/ruby_file.feature
48
+ - features/support/env.rb
49
+ - fixtures/another-build-dir-app/_BUILD_DIR_REQUIED_
50
+ - fixtures/another-build-dir-app/config.rb
51
+ - fixtures/another-build-dir-app/source/target.erb
52
+ - fixtures/another-build-dir-app/source/target.txt.erb
53
+ - fixtures/avoid-layout-app/config.rb
54
+ - fixtures/avoid-layout-app/source/layouts/layout.erb
55
+ - fixtures/avoid-layout-app/source/target.erb
56
+ - fixtures/avoid-layout-app/source/target.txt.erb
57
+ - fixtures/erb-app/config.rb
58
+ - fixtures/erb-app/source/.htaccess.erb
59
+ - fixtures/erb-app/source/.target.erb
60
+ - fixtures/erb-app/source/target.erb
61
+ - fixtures/erb-app/source/target.txt.erb
62
+ - fixtures/erb-app/source/target_cap.ERB
63
+ - fixtures/erb-app/source/target_inner_.erb_.erb
64
+ - fixtures/erb-app/source/target_no_tag.erb
65
+ - fixtures/erb-app/source/target_no_tag.txt.erb
66
+ - fixtures/erb-path-app/config.rb
67
+ - fixtures/erb-path-app/source/sub/target.erb
68
+ - fixtures/erb-path-app/source/sub/target.txt.erb
69
+ - fixtures/html-erb-app/config.rb
70
+ - fixtures/html-erb-app/source/target.html.erb
71
+ - fixtures/no-erb-app/config.rb
72
+ - fixtures/no-erb-app/source/target
73
+ - fixtures/no-erb-app/source/target.erb.txt
74
+ - fixtures/no-erb-app/source/target.txt
75
+ - fixtures/no-file-app/config.rb
76
+ - fixtures/no-file-app/source/target.erb
77
+ - fixtures/no-target-app/config.rb
78
+ - fixtures/no-target-app/source/target.erb
79
+ - fixtures/no-target-app/source/target.txt.erb
80
+ - fixtures/ruby-file-app/config.rb
81
+ - fixtures/ruby-file-app/source/target.rb
82
+ - fixtures/ruby-file-app/source/target.txt
83
+ - lib/middleman-extensionless-helper.rb
84
+ - lib/middleman-extensionless-helper/extension.rb
85
+ - lib/middleman-extensionless-helper/version.rb
86
+ - lib/middleman_extension.rb
87
+ - middleman-extensionless-helper.gemspec
88
+ homepage: https://github.com/AT-AT/middleman-extensionless-helper
89
+ licenses: []
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.5.1
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: A Middleman extension to remove an automatically added content extension
111
+ test_files:
112
+ - features/another_build_dir.feature
113
+ - features/avoid-layout.feature
114
+ - features/erb-path.feature
115
+ - features/erb.feature
116
+ - features/html_erb.feature
117
+ - features/no_erb.feature
118
+ - features/no_file.feature
119
+ - features/no_target.feature
120
+ - features/ruby_file.feature
121
+ - features/support/env.rb
122
+ - fixtures/another-build-dir-app/_BUILD_DIR_REQUIED_
123
+ - fixtures/another-build-dir-app/config.rb
124
+ - fixtures/another-build-dir-app/source/target.erb
125
+ - fixtures/another-build-dir-app/source/target.txt.erb
126
+ - fixtures/avoid-layout-app/config.rb
127
+ - fixtures/avoid-layout-app/source/layouts/layout.erb
128
+ - fixtures/avoid-layout-app/source/target.erb
129
+ - fixtures/avoid-layout-app/source/target.txt.erb
130
+ - fixtures/erb-app/config.rb
131
+ - fixtures/erb-app/source/.htaccess.erb
132
+ - fixtures/erb-app/source/.target.erb
133
+ - fixtures/erb-app/source/target.erb
134
+ - fixtures/erb-app/source/target.txt.erb
135
+ - fixtures/erb-app/source/target_cap.ERB
136
+ - fixtures/erb-app/source/target_inner_.erb_.erb
137
+ - fixtures/erb-app/source/target_no_tag.erb
138
+ - fixtures/erb-app/source/target_no_tag.txt.erb
139
+ - fixtures/erb-path-app/config.rb
140
+ - fixtures/erb-path-app/source/sub/target.erb
141
+ - fixtures/erb-path-app/source/sub/target.txt.erb
142
+ - fixtures/html-erb-app/config.rb
143
+ - fixtures/html-erb-app/source/target.html.erb
144
+ - fixtures/no-erb-app/config.rb
145
+ - fixtures/no-erb-app/source/target
146
+ - fixtures/no-erb-app/source/target.erb.txt
147
+ - fixtures/no-erb-app/source/target.txt
148
+ - fixtures/no-file-app/config.rb
149
+ - fixtures/no-file-app/source/target.erb
150
+ - fixtures/no-target-app/config.rb
151
+ - fixtures/no-target-app/source/target.erb
152
+ - fixtures/no-target-app/source/target.txt.erb
153
+ - fixtures/ruby-file-app/config.rb
154
+ - fixtures/ruby-file-app/source/target.rb
155
+ - fixtures/ruby-file-app/source/target.txt
156
+ has_rdoc: