nanoc-oo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.gitignore +17 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +31 -0
  6. data/Rakefile +1 -0
  7. data/bin/nanoc-oo +17 -0
  8. data/cucumber.yml +8 -0
  9. data/data/nanoc-oo/wrapper/Rules +115 -0
  10. data/data/nanoc-oo/wrapper/lib/classes/1_page.rb +198 -0
  11. data/data/nanoc-oo/wrapper/lib/fake_dir.rb +27 -0
  12. data/data/nanoc-oo/wrapper/lib/fake_item.rb +39 -0
  13. data/data/nanoc-oo/wrapper/lib/fake_items.rb +22 -0
  14. data/data/nanoc-oo/wrapper/lib/filter_for.rb +14 -0
  15. data/data/nanoc-oo/wrapper/lib/item_class.rb +22 -0
  16. data/features/_related_tests.feature +32 -0
  17. data/features/composite_file.example +82 -0
  18. data/features/move_children.example +43 -0
  19. data/features/paginate_article.example +86 -0
  20. data/features/step_definitions/complex_steps.rb +23 -0
  21. data/features/step_definitions/nanoc-oo_steps.rb +9 -0
  22. data/features/step_definitions/nanoc_steps.rb +22 -0
  23. data/features/step_definitions/steps.rb +1 -0
  24. data/features/support/env.rb +25 -0
  25. data/features/support/my_extension.rb +16 -0
  26. data/features/support/nice_steps.rb +14 -0
  27. data/lib/nanoc-oo/version.rb +3 -0
  28. data/lib/nanoc-oo.rb +25 -0
  29. data/nanoc-oo.gemspec +32 -0
  30. data/old-README.md +72 -0
  31. data/spec/add_item_spec.rb +97 -0
  32. data/spec/cli/all_spec.rb +57 -0
  33. data/spec/item_children_and_comiling_spec.rb +97 -0
  34. data/spec/items_configuration_spec.rb +239 -0
  35. data/spec/layouts_spec.rb +50 -0
  36. data/spec/rspec/compiler_spec.rb +8 -0
  37. data/spec/rspec/nanoc_spec.rb +13 -0
  38. data/spec/rspec/wrapper_spec.rb +15 -0
  39. data/spec/support/0_coverage.rb +18 -0
  40. data/spec/support/1_config.rb +27 -0
  41. data/spec/support/2_nanoc.rb +27 -0
  42. data/spec/support/3_wrapper.rb +17 -0
  43. data/spec/support/4_compiler.rb +16 -0
  44. data/spec/support/5_temp_files.rb +51 -0
  45. data/spec/support/6_temp_helpers.rb +98 -0
  46. data/spec/support/all.rb +22 -0
  47. data/spec/unit/fake_dir_spec.rb +45 -0
  48. data/spec/unit/fake_item_spec.rb +62 -0
  49. data/spec/unit/fake_items_spec.rb +38 -0
  50. data/spec/unit/filter_for_spec.rb +12 -0
  51. data/spec/unit/item_class_spec.rb +42 -0
  52. data/spec/unit/page_spec.rb +96 -0
  53. data/spec/unit/temp_files_spec.rb +107 -0
  54. metadata +278 -0
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nanoc-oo.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # NanocOO
2
+
3
+ TODO: Write a gem description
4
+ TODO: Write a gem description
5
+ TODO: Write a gem description
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'nanoc-oo'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install nanoc-oo
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/nanoc-oo ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ require 'nanoc-oo'
3
+ require 'thor/group'
4
+
5
+ class CLI < Thor::Group
6
+ argument :name, type: :string, desc: 'directory name for new site'
7
+ class_option :blank, type: :boolean, default: false, desc: 'without content files'
8
+ desc 'creates nanoc site with object-oriented wrapper'
9
+
10
+ def create_it
11
+ NanocOO.create_site name, options[:blank]
12
+ end
13
+
14
+ def self.banner; super.sub('cli ','') end
15
+ end
16
+
17
+ ARGV.empty?? CLI.usage : CLI.start
data/cucumber.yml ADDED
@@ -0,0 +1,8 @@
1
+ <%
2
+ rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3
+ rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4
+ std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
5
+ %>
6
+ default: <%= std_opts %> features
7
+ wip: --tags @wip:3 --wip features
8
+ rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ ###############
5
+ # Odd #
6
+ ###############
7
+
8
+ class Nanoc::Item
9
+ def +@
10
+ self[:object]
11
+ end
12
+ end
13
+
14
+ #compile('/'){ layout 'default' }; route('/'){'/index.html'}
15
+ #compile('/stylesheet/'){}; route('/stylesheet/'){'/style.css'}
16
+
17
+ @file = '../log.txt'
18
+ def log?
19
+ File.exist?(@file) ? File.read(@file) : ''
20
+ end
21
+ def log data
22
+ File.write @file, log? + "\n#{ data }"
23
+ end
24
+
25
+ module Preprocessor # one .preprocess per item!
26
+
27
+ def self.preprocess! context, classes
28
+
29
+ while item = context.items.find { |item| !(+item) || !(+item).processed? }
30
+ prepare item, classes
31
+ (+item).do_preprocess context
32
+ end
33
+
34
+ fix_children context # after preprocessing finished
35
+ end
36
+
37
+ def self.prepare item, classes
38
+ item[:object] = classes[item].new(item) unless +item
39
+ item
40
+ end
41
+ def self.fix_children context
42
+ context.items.each do |item|
43
+ (+item).fix_children context
44
+ end
45
+ end
46
+ end
47
+
48
+ module ::Builder
49
+
50
+ def self.build! item, context, items_context
51
+
52
+ unless item.is_a? FakeDir
53
+
54
+ context.compile (+item).identifier do
55
+ (+item).compile self
56
+ end
57
+
58
+ context.route (+item).identifier do
59
+ (+item).route
60
+ end
61
+ end
62
+
63
+ (+item).compile_children context, items_context
64
+ end
65
+ end
66
+
67
+ def root items, classes
68
+ items.find { |item| item.identifier == '/' } or Preprocessor.prepare Nanoc::Item.new('', { hidden: true }, '/'), classes
69
+ end
70
+
71
+
72
+ #################
73
+ # Layouts #
74
+ #################
75
+ #
76
+ # The first matching rule is used:
77
+ # layout '*', :erb
78
+ # layout '/default/', :slim
79
+ # layout '/default/', :haml, format: :html5
80
+ # layout %r{^/_.+/$}, :erb
81
+ # /default/ may be layouts/default.with-any-extension
82
+ # all unmatched layouts will be compiled using filter determined by extension:
83
+ #
84
+
85
+ FakeItems.new('layouts').items.each do |item|
86
+ layout item.identifier, FilterFor[item.file]
87
+ end
88
+
89
+
90
+ #################
91
+ # Items #
92
+ #################
93
+
94
+ fake = FakeItems.new('content')
95
+ classes = ItemClass.new
96
+
97
+
98
+ ##################
99
+ # Preprocess #
100
+ ##################
101
+
102
+ Preprocessor.preprocess! fake, classes
103
+
104
+ preprocess do
105
+ Preprocessor.preprocess! self, classes
106
+ end
107
+
108
+
109
+ ###################
110
+ # Compile/Route #
111
+ ###################
112
+ #
113
+ # FIXME "if" just for specs, to prevent crashes
114
+ #
115
+ Builder.build! root(fake.items, classes), self, fake if fake.items.count > 0
@@ -0,0 +1,198 @@
1
+ def is_binary_file? file
2
+ require 'ptools'
3
+ File.binary? file
4
+ end
5
+
6
+ # module Hidable
7
+ # def route *a
8
+ # return nil if hidden?
9
+ # super
10
+ # end
11
+
12
+ # # def compile *a
13
+ # # return nil if hidden?
14
+ # # super
15
+ # # end
16
+
17
+ # private
18
+ # def hidden?
19
+ # # item[:hidden] == true
20
+ # end
21
+ # end
22
+
23
+ module PageDefaults
24
+ def route
25
+ return nil if self.class::ROUTE == false
26
+ self.class::ROUTE or identifier.chop + (html?? '/index.html' : ".#{extension}")
27
+ end
28
+
29
+ #def item_path
30
+ # identifier[%r|(/.*/).*?/|]
31
+ #end
32
+ #def item_name
33
+ # identifier[%r|/.*(/.*?/)|]
34
+ #end
35
+
36
+ def compile_children context, items_context
37
+ children(items_context).each do |child|
38
+ ::Builder.build! child, context, items_context
39
+ end
40
+ end
41
+
42
+ def children context=nil
43
+ return @fixed_children if @fixed_children
44
+ raise 'context is needed to get children before preprocessing is finished!' unless context
45
+ direct_children context
46
+ end
47
+
48
+
49
+ def fix_children context
50
+ @fixed_children = children context
51
+ end
52
+
53
+
54
+ def direct_children context
55
+ context.items.select { |items| items.identifier =~ %r|^#{ Regexp.escape identifier }[^/]+/$| }
56
+ end
57
+
58
+ def compile context
59
+ apply_filter context
60
+ apply_layout context
61
+ after_compile context
62
+ end
63
+
64
+ def apply_filter context
65
+ context.filter filter if filter
66
+ end
67
+ def filter
68
+ return self.class::FILTER if self.class::FILTER
69
+ return @@filters[last_extension] if @@filters[last_extension]
70
+ end
71
+ def apply_layout context
72
+ context.layout layout if layout
73
+ end
74
+ def layout
75
+ self.class::LAYOUT if defined? self.class::LAYOUT
76
+ end
77
+ def after_compile context
78
+ context.filter :relativize_paths, type: kind if kind
79
+ end
80
+
81
+ def kind
82
+ case
83
+ when html? then :html
84
+ when css? then :css
85
+ end
86
+ end
87
+
88
+
89
+ def css?
90
+ really_css?
91
+ end
92
+
93
+ def really_css?
94
+ extension.split('.').find { |ext| ext =~ /^(#{ CSS_EXTENSIONS })$/ } ? true : false
95
+ end
96
+
97
+
98
+
99
+ # uses FakeItem#file or NanocItem#[:binary]
100
+ #
101
+ def binary?
102
+ item.respond_to?(:file) ? is_binary_file?(item.file) : item[:binary]
103
+ end
104
+
105
+ def html?
106
+ really_html?
107
+ end
108
+
109
+ def really_html?
110
+ extension.split('.').find { |ext| ext =~ /^(#{ HTML_EXTENSIONS })$/ } ? true : false
111
+ end
112
+
113
+ def extension
114
+ self.class::EXT or item[:extension] or ''
115
+ end
116
+
117
+ def last_extension
118
+ extension[/[.](.+?)$/, 1] or extension
119
+ end
120
+
121
+ FILTER = nil
122
+ ROUTE = nil
123
+ EXT = nil
124
+ CSS_EXTENSIONS = 'css|sass|scss'
125
+ HTML_EXTENSIONS = 'html|htm|slim|haml|md'
126
+ PRIORITY = 0
127
+ @@filters = {'md' => :kramdown, 'slim' => :slim, 'erb' => :erb}
128
+ end
129
+
130
+ class Page
131
+ include PageDefaults
132
+ # include Hidable
133
+ attr_reader :item
134
+
135
+ def initialize item
136
+ @item = item
137
+ end
138
+
139
+ def self.create context, *params
140
+ context.items << item = Nanoc::Item.new(*params)
141
+ item[:object] = self.new item
142
+ end
143
+
144
+ def preprocess context
145
+ end
146
+
147
+ def do_preprocess context
148
+ preprocess context
149
+ ensure
150
+ @processed = true
151
+ end
152
+
153
+ def processed?
154
+ @processed
155
+ end
156
+
157
+ def identifier
158
+ item.identifier
159
+ end
160
+ def identifier= value
161
+ item.identifier = value
162
+ end
163
+
164
+ def self.accept? identifier
165
+ return false unless mask = good_id
166
+ identifier =~ mask ? true : false
167
+ end
168
+
169
+ def self.good_id
170
+ id = self::GOOD_ID
171
+ case id
172
+ when String
173
+ id.gsub!('**','.+') # any level
174
+ id.gsub!('*','[^/]+') # one level
175
+ id = "/#{id}" unless id[0] == '/'
176
+ id = "#{id}/" unless id[-1] == '/'
177
+ /^#{id}$/
178
+ else
179
+ id
180
+ end
181
+ end
182
+
183
+ def representation
184
+ rep
185
+ end
186
+ def rep
187
+ :default
188
+ end
189
+ end
190
+
191
+ class UndefinedPage < Page
192
+ PRIORITY = fixnum_min = -(2**(0.size * 8 -2))
193
+ def self.accept? *a; true end
194
+
195
+ def route *a; end
196
+ def compile *a; end
197
+ def preprocess *a; end
198
+ end
@@ -0,0 +1,27 @@
1
+ class FakeDir
2
+ attr_reader :file
3
+ attr_accessor :identifier
4
+
5
+ def initialize file
6
+ @file = file
7
+ @values = {}
8
+ @identifier = get_identifier
9
+ end
10
+
11
+ def +@
12
+ @values[:object]
13
+ end
14
+ def []= key, value
15
+ @values[key] = value
16
+ end
17
+ def [] key
18
+ @values[key]
19
+ end
20
+
21
+ private
22
+ def get_identifier
23
+ dir = @file.sub(/.+?\//, '/')
24
+ dir << '/' if dir[-1] != '/'
25
+ dir
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ class FakeItem
2
+ attr_reader :file
3
+ attr_accessor :identifier
4
+
5
+ def initialize file
6
+ @file = file
7
+ @identifier = get_identifier
8
+ @values = {}
9
+ end
10
+
11
+ def binary?
12
+ require 'ptools'
13
+ File.binary?(file)
14
+ end
15
+
16
+ def raw_content
17
+ File.read file
18
+ end
19
+
20
+ def +@
21
+ @values[:object]
22
+ end
23
+ def []= key, value
24
+ @values[key] = value
25
+ end
26
+ def [] key
27
+ return extension if key == :extension
28
+ @values[key]
29
+ end
30
+
31
+ private
32
+ def get_identifier
33
+ (@file.sub(/.+?\//, '/').sub(/\.[^\/]+/, '') + '/').sub(%r[/index/$], '/')
34
+ end
35
+
36
+ def extension
37
+ @file[/\.([^\/]+)$/, 1].to_s
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ class FakeItems
2
+ attr_reader :items
3
+
4
+ def initialize where, params={nanoc:false}
5
+ @params = params
6
+ all = Dir["#{where}/**/*"]
7
+ files = all.reject { |those| File.directory? those }.map { |item| create item } # FakeItem.new item }
8
+ dirs = all.select { |those| File.directory? those }.map { |item| FakeDir.new item }
9
+ dirs.reject! { |dir| files.find { |file| file.identifier == dir.identifier } }
10
+ @items = files + dirs
11
+ end
12
+
13
+ def create item
14
+ fake = FakeItem.new item
15
+ if @params[:nanoc] && defined? Nanoc
16
+ content = fake.binary?? fake.file : File.read(fake.file)
17
+ Nanoc::Item.new content, {}, fake.identifier
18
+ else
19
+ fake
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module FilterFor
2
+ extend self
3
+ KNOWN_FILTERS = { 'html' => :erb, 'htm' => :erb }
4
+
5
+ def [] file
6
+ filter_ext File.extname file
7
+ end
8
+
9
+ private
10
+ def filter_ext ext
11
+ ext = ext.sub(/^\./,'')
12
+ KNOWN_FILTERS[ext] or ext.to_sym
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ class Class
2
+ def subclasses
3
+ ObjectSpace.each_object(Class).select { |klass| klass < self }
4
+ end
5
+ end
6
+
7
+ class ItemClass
8
+ attr_reader :classes
9
+
10
+ def initialize
11
+ @classes = find_classes
12
+ end
13
+
14
+ def [] item
15
+ @classes.find { |that| that.accept? item.identifier }
16
+ end
17
+
18
+ private
19
+ def find_classes
20
+ Page.subclasses.sort_by { |x| x::PRIORITY }.reverse
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ Feature: related tests
2
+
3
+ Scenario Outline: nanoc is ok
4
+ When I successfully run `ruby -S nanoc <command>`
5
+ Then the output should contain "<success>"
6
+
7
+ Examples:
8
+ | command | success |
9
+ | -v | 2007 |
10
+ | cs temp | Enjoy! |
11
+
12
+
13
+ Scenario: wrapper is ok
14
+ Given I have a blank wrapped nanoc site
15
+ And a directory named "lib/classes" should exist
16
+ And a file named "lib/classes/hide_all.rb" with:
17
+ """
18
+ class HideAll < Page
19
+ GOOD_ID = // # any
20
+ def route; nil end
21
+ end
22
+ """
23
+ When I successfully compile it
24
+ Then the file "output/index.html" should not exist
25
+ Then the file "output/style.css" should not exist
26
+
27
+
28
+ Scenario: steps are ok
29
+ Given I have a default nanoc site
30
+ When I successfully compile it
31
+ Then a file named "output/index.html" should exist
32
+ Then a file named "output/style.css" should exist
@@ -0,0 +1,82 @@
1
+ Feature: composite file example
2
+
3
+ Background:
4
+ Given I have a blank wrapped nanoc site
5
+ And the folowing are input files:
6
+ """
7
+ content/style/one.sass
8
+ content/style/two.sass
9
+ content/style/three.sass
10
+ content/style/index.erb
11
+ """
12
+ And the folowing are expected output files:
13
+ """
14
+ output/style.css
15
+ """
16
+
17
+ Scenario:
18
+ Given a file named "lib/classes/style.rb" with:
19
+ """
20
+ # different items with same routes???
21
+ # INDEX = ...
22
+ # create item?
23
+ # compile_ext / route_ext ???
24
+ # EXT = 'css' filter an route
25
+ # NAME = 'style.css' # used by routing and ext ??
26
+ # INDEX = ...
27
+ # LAYOUT = ...
28
+ #%r|^/style/.| # '/style/.'
29
+ # '*/style' < 1 level deep
30
+ # '**/style' < n levels deep
31
+
32
+ #%r|^/style/.| # <<<<<<<<<<< get rid of regexp! '*/style/*'
33
+
34
+
35
+ class Style < Page
36
+ GOOD_ID = '/style/'
37
+ ROUTE = '/style.css'
38
+ end
39
+
40
+ class SubStyle < Page
41
+ GOOD_ID = 'style/**' # == '/style/**/' (boundary slashes are optional: se == /se == se/ == /se/ )
42
+ ROUTE = false # nil - default action, false - dont create output file
43
+ FILTER = :sass # or @@filters['sass'] = :sass # filter by ext
44
+ end
45
+ """
46
+ And a file named "content/style/index.erb" with:
47
+ """
48
+ <%= (+item).children.map(&:compiled_content).join "\n" %>
49
+ """
50
+ And a file named "content/style/one.sass" with:
51
+ """
52
+ html
53
+ color: red
54
+ """
55
+ And a file named "content/style/two.sass" with:
56
+ """
57
+ html
58
+ color: green
59
+ """
60
+ And a file named "content/style/three.sass" with:
61
+ """
62
+ html
63
+ color: blue
64
+ """
65
+ When I successfully compile it
66
+ Then input are the only files in "content" directory
67
+ And expected output are the only files in "output" directory
68
+ Then the file "output/style.css" should contain:
69
+ """
70
+ html {
71
+ color: red; }
72
+ """
73
+ Then the file "output/style.css" should contain:
74
+ """
75
+ html {
76
+ color: green; }
77
+ """
78
+ Then the file "output/style.css" should contain:
79
+ """
80
+ html {
81
+ color: blue; }
82
+ """