proton 0.3.0.rc1

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 (126) hide show
  1. data/AUTHORS +6 -0
  2. data/HISTORY.md +200 -0
  3. data/README.md +75 -0
  4. data/Rakefile +5 -0
  5. data/TODO.md +6 -0
  6. data/bin/proton +7 -0
  7. data/data/new_site/Protonfile +12 -0
  8. data/data/new_site/README.md +10 -0
  9. data/data/new_site/_layouts/default.haml +28 -0
  10. data/data/new_site/index.haml +5 -0
  11. data/data/rack/Gemfile +2 -0
  12. data/data/rack/Gemfile.lock +40 -0
  13. data/data/rack/config.ru +24 -0
  14. data/lib/proton.rb +78 -0
  15. data/lib/proton/cli.rb +227 -0
  16. data/lib/proton/cli/helpers.rb +89 -0
  17. data/lib/proton/compass_support.rb +8 -0
  18. data/lib/proton/config.rb +116 -0
  19. data/lib/proton/helpers.rb +126 -0
  20. data/lib/proton/layout.rb +20 -0
  21. data/lib/proton/meta.rb +17 -0
  22. data/lib/proton/page.rb +431 -0
  23. data/lib/proton/partial.rb +12 -0
  24. data/lib/proton/project.rb +176 -0
  25. data/lib/proton/server.rb +99 -0
  26. data/lib/proton/set.rb +32 -0
  27. data/lib/proton/version.rb +13 -0
  28. data/test/fixture/build_options/control/page.html +0 -0
  29. data/test/fixture/build_options/control/style.css +1 -0
  30. data/test/fixture/build_options/hyde.conf +18 -0
  31. data/test/fixture/build_options/site/page.haml +0 -0
  32. data/test/fixture/build_options/site/style.scss +1 -0
  33. data/test/fixture/compass/hyde.conf +4 -0
  34. data/test/fixture/compass/site/style.scss +5 -0
  35. data/test/fixture/empty_config/hyde.conf +0 -0
  36. data/test/fixture/extensions/control/index.html +1 -0
  37. data/test/fixture/extensions/extensions/a/a.rb +1 -0
  38. data/test/fixture/extensions/extensions/hi.rb +1 -0
  39. data/test/fixture/extensions/hyde.conf +8 -0
  40. data/test/fixture/extensions/site/index.haml +1 -0
  41. data/test/fixture/fail_type/control/about/index.html +2 -0
  42. data/test/fixture/fail_type/control/about/us.html +2 -0
  43. data/test/fixture/fail_type/control/index.html +1 -0
  44. data/test/fixture/fail_type/hyde.conf +8 -0
  45. data/test/fixture/fail_type/site/index.haml +4 -0
  46. data/test/fixture/high_version/hyde.conf +1 -0
  47. data/test/fixture/high_version_2/hyde.conf +1 -0
  48. data/test/fixture/html/control/index.html +2 -0
  49. data/test/fixture/html/hyde.conf +8 -0
  50. data/test/fixture/html/site/index.html +2 -0
  51. data/test/fixture/ignores/control/about.html +1 -0
  52. data/test/fixture/ignores/hyde.conf +10 -0
  53. data/test/fixture/ignores/site/about.haml +1 -0
  54. data/test/fixture/ignores/site/hi.haml +1 -0
  55. data/test/fixture/metadata/control/index.html +4 -0
  56. data/test/fixture/metadata/hyde.conf +8 -0
  57. data/test/fixture/metadata/site/index.haml +8 -0
  58. data/test/fixture/nested_layout/control/index.html +2 -0
  59. data/test/fixture/nested_layout/hyde.conf +9 -0
  60. data/test/fixture/nested_layout/layouts/default.haml +2 -0
  61. data/test/fixture/nested_layout/layouts/post.haml +3 -0
  62. data/test/fixture/nested_layout/site/index.haml +4 -0
  63. data/test/fixture/one/control/about/index.css +1 -0
  64. data/test/fixture/one/control/about/us.html +1 -0
  65. data/test/fixture/one/control/cheers.html +5 -0
  66. data/test/fixture/one/control/css/bar.css +0 -0
  67. data/test/fixture/one/control/css/style.css +1 -0
  68. data/test/fixture/one/control/hello.html +5 -0
  69. data/test/fixture/one/control/hi.html +1 -0
  70. data/test/fixture/one/control/images/bar.gif +0 -0
  71. data/test/fixture/one/control/images/baz.png +0 -0
  72. data/test/fixture/one/control/images/foo.jpg +0 -0
  73. data/test/fixture/one/control/index.html +7 -0
  74. data/test/fixture/one/hyde.conf +9 -0
  75. data/test/fixture/one/layouts/default.haml +4 -0
  76. data/test/fixture/one/partials/menu.haml +3 -0
  77. data/test/fixture/one/public/about/index.css +1 -0
  78. data/test/fixture/one/public/about/us.html +1 -0
  79. data/test/fixture/one/public/cheers.html +5 -0
  80. data/test/fixture/one/public/css/bar.css +0 -0
  81. data/test/fixture/one/public/css/style.css +1 -0
  82. data/test/fixture/one/public/hello.html +5 -0
  83. data/test/fixture/one/public/hi.html +1 -0
  84. data/test/fixture/one/public/images/bar.gif +0 -0
  85. data/test/fixture/one/public/images/baz.png +0 -0
  86. data/test/fixture/one/public/images/foo.jpg +0 -0
  87. data/test/fixture/one/public/index.html +7 -0
  88. data/test/fixture/one/site/about/index.scss +1 -0
  89. data/test/fixture/one/site/about/us.haml +3 -0
  90. data/test/fixture/one/site/cheers.html.haml +1 -0
  91. data/test/fixture/one/site/css/bar.scss +0 -0
  92. data/test/fixture/one/site/css/style.scss +2 -0
  93. data/test/fixture/one/site/hello.haml +3 -0
  94. data/test/fixture/one/site/hi.html +3 -0
  95. data/test/fixture/one/site/images/bar.gif +0 -0
  96. data/test/fixture/one/site/images/baz.png +0 -0
  97. data/test/fixture/one/site/images/foo.jpg +0 -0
  98. data/test/fixture/one/site/index.haml +7 -0
  99. data/test/fixture/parent/control/about/index.html +2 -0
  100. data/test/fixture/parent/control/about/us.html +2 -0
  101. data/test/fixture/parent/control/index.html +1 -0
  102. data/test/fixture/parent/hyde.conf +8 -0
  103. data/test/fixture/parent/site/about/index.haml +3 -0
  104. data/test/fixture/parent/site/about/us.haml +3 -0
  105. data/test/fixture/parent/site/index.haml +3 -0
  106. data/test/fixture/sort/control/about.html +6 -0
  107. data/test/fixture/sort/control/about/hardy.html +1 -0
  108. data/test/fixture/sort/control/about/intrepid.html +1 -0
  109. data/test/fixture/sort/hyde.conf +8 -0
  110. data/test/fixture/sort/site/about.haml +3 -0
  111. data/test/fixture/sort/site/about/hardy.haml +4 -0
  112. data/test/fixture/sort/site/about/intrepid.haml +4 -0
  113. data/test/fixture/subclass/control/index.html +1 -0
  114. data/test/fixture/subclass/extensions/a/a.rb +12 -0
  115. data/test/fixture/subclass/hyde.conf +9 -0
  116. data/test/fixture/subclass/layouts/default.haml +1 -0
  117. data/test/fixture/subclass/layouts/post.haml +1 -0
  118. data/test/fixture/subclass/site/index.haml +4 -0
  119. data/test/helper.rb +36 -0
  120. data/test/unit/build_options_test.rb +18 -0
  121. data/test/unit/extensions_test.rb +17 -0
  122. data/test/unit/fixture_test.rb +122 -0
  123. data/test/unit/page_test.rb +58 -0
  124. data/test/unit/proton_test.rb +27 -0
  125. data/test/unit/set_test.rb +26 -0
  126. metadata +301 -0
@@ -0,0 +1,12 @@
1
+ class Proton
2
+ class Partial < Layout
3
+ protected
4
+ def self.root_path(project, *a)
5
+ project.path(:partials, *a)
6
+ end
7
+
8
+ def default_layout
9
+ nil
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,176 @@
1
+ class Proton
2
+ # Class: Proton::Project
3
+ # A project.
4
+ #
5
+ # ## Common usage
6
+ #
7
+ # Instanciating:
8
+ #
9
+ # project = Project.new('~/spur')
10
+ # project == Proton.project # the last defined project
11
+ #
12
+ # Building:
13
+ #
14
+ # project.build
15
+ # project.build { |file| puts "Building #{file}..." }
16
+ #
17
+ # Getting pages:
18
+ #
19
+ # Proton::Page['/index.html'] # ~/spur/index.md; uses Proton.project
20
+ #
21
+ # Configuration:
22
+ #
23
+ # project.config_file # ~/spur/hyde.conf
24
+ # project.config # Config from above file (OpenStruct)
25
+ # project.config.site_path
26
+ #
27
+ # Paths:
28
+ #
29
+ # project.path(:site) # ~/spur/site (based on config site_path)
30
+ # project.path(:extensions)
31
+ #
32
+ # project.root('a/b', 'c') # ~/spur/a/b/c
33
+ #
34
+ # Indexing:
35
+ #
36
+ # project.pages # [<#Page>, <#Page>, ...]
37
+ # project.files # ['/index.md', '/style.sass', ...]
38
+ # # (only site files)
39
+ # project.ignored_files
40
+ #
41
+ class Project
42
+ def initialize(root=Dir.pwd)
43
+ @root = root
44
+ Proton.project = self
45
+
46
+ validate_version
47
+ load_extensions
48
+
49
+ load File.expand_path('../compass_support.rb', __FILE__)
50
+ end
51
+
52
+ def validate_version
53
+ return unless config_file?
54
+ req = config.requirement.to_s
55
+
56
+ v = lambda { |version| Gem::Version.new version }
57
+
58
+ if req.empty?
59
+ # pass
60
+ elsif v[req] < v["0.1"]
61
+ raise LegacyError, "This is a legacy project"
62
+ elsif v[req] > v[Proton.version]
63
+ raise VersionError, "You will need Proton version >= #{req} for this project."
64
+ end
65
+ end
66
+
67
+ def load_extensions
68
+ path = path(:extensions)
69
+
70
+ ( Dir[path(:extensions, '*.rb')] +
71
+ Dir[path(:extensions, '*', '*.rb')]
72
+ ).sort.each { |f| require f } if path
73
+ end
74
+
75
+ # Method: config_file (Proton::Project)
76
+ # Returns the configuration file for the project.
77
+
78
+ def config_file
79
+ try = lambda { |path| p = root(path); p if File.file?(p) }
80
+ Proton::CONFIG_FILES.inject(nil) { |acc, file| acc ||= try[file] }
81
+ end
82
+
83
+ def config_file?
84
+ config_file
85
+ end
86
+
87
+ # Method: config (Proton::Project)
88
+ # Returns a Proton::Config instance.
89
+
90
+ def config
91
+ @config ||= Config.load(config_file)
92
+ end
93
+
94
+ # Method: path (Proton::Project)
95
+ # Returns the path for a certain aspect.
96
+ #
97
+ # ## Example
98
+ #
99
+ # Proton.project.path(:site)
100
+
101
+ def path(what, *a)
102
+ return nil unless [:output, :site, :layouts, :extensions, :partials].include?(what)
103
+ path = config.send(:"#{what}_path")
104
+ root path, *a if path
105
+ end
106
+
107
+ # Method: root (Proton::Project)
108
+ # Returns the root path of the project.
109
+
110
+ def root(*args)
111
+ File.join @root, *(args.compact)
112
+ end
113
+
114
+ # Method: pages (Proton::Project)
115
+ # Returns the pages for the project.
116
+
117
+ def pages
118
+ files.map { |f| Page[f, self] }.compact
119
+ end
120
+
121
+ # Method: files (Proton::Project)
122
+ # Returns the site files for the project, free from the ignored files.
123
+
124
+ def files
125
+ files = Dir[File.join(path(:site), '**', '*')]
126
+ files = files.select { |f| File.file?(f) }
127
+ files = files.map { |f| File.expand_path(f) }
128
+ files - ignored_files
129
+ end
130
+
131
+ # Method: ignored_files (Proton::Project)
132
+ # Returns the files to be ignored for the project.
133
+
134
+ def ignored_files
135
+ specs = [*config.ignore].map { |s| root(s) }
136
+ specs << config_file
137
+
138
+ # Ignore the standard files
139
+ [:layouts, :extensions, :partials, :output].each do |aspect|
140
+ specs << File.join(config.send(:"#{aspect}_path"), '**/*') if path(aspect) && path(aspect) != path(:site)
141
+ end
142
+
143
+ # Ignore dotfiles and hyde.conf files by default
144
+ specs += %w[.* _* *~ README* /config.ru]
145
+ specs += Proton::CONFIG_FILES.map { |s| "/#{s}" }
146
+
147
+ specs.compact.map { |s| glob(s) }.flatten.uniq
148
+ end
149
+
150
+ # Method: build (Proton::Project)
151
+ # Builds.
152
+
153
+ def build(&blk)
154
+ pages.each do |page|
155
+ yield page
156
+ page.write
157
+ end
158
+ ensure
159
+ build_cleanup
160
+ end
161
+
162
+ protected
163
+ def glob(str)
164
+ if str[0] == '/'
165
+ Dir[str] + Dir[root(str)] + Dir["#{root(str)}/**"]
166
+ else
167
+ Dir[root("**/#{str}")] + Dir[root("**/#{str}/**")]
168
+ end
169
+ end
170
+
171
+ def build_cleanup
172
+ FileUtils.rm_rf '.sass_cache'
173
+ end
174
+ end
175
+ end
176
+
@@ -0,0 +1,99 @@
1
+ require 'cuba'
2
+ require 'rack'
3
+ require 'proton'
4
+
5
+ # Module: Proton::Server
6
+ # The Proton server rack application.
7
+
8
+ class Proton
9
+ Server = Cuba.dup
10
+
11
+ module Server; end
12
+
13
+ module Server::PageHelpers
14
+ def not_found
15
+ show_status nil
16
+ res.status = 404
17
+ res.write "<h1>File Not Found</h1><p>The path <code>#{env['PATH_INFO']}</code> was not found." + " "*1024
18
+ end
19
+
20
+ def options
21
+ @options ||= Hash.new
22
+ end
23
+
24
+ def show_status(page)
25
+ return if options[:quiet]
26
+ path = env['PATH_INFO']
27
+ return if path == '/favicon.ico'
28
+
29
+ status = page ? "\033[0;32m[ OK ]" : "\033[0;31m[404 ]"
30
+ verb = get ? 'GET ' : (post ? 'POST' : '')
31
+ puts "%s\033[0;m %s %s" % [ status, verb, env['PATH_INFO'] ]
32
+ puts " src: #{page.filepath} (#{page.tilt_engine_name})" if page && page.tilt?
33
+ end
34
+
35
+ def mime_type_for(page)
36
+ type = page.mime_type
37
+ type ||= Rack::Mime::MIME_TYPES[File.extname(page.file)]
38
+ type
39
+ end
40
+
41
+ def server
42
+ Proton::Server
43
+ end
44
+ end
45
+
46
+ module Proton::Server
47
+ Ron.send :include, PageHelpers
48
+
49
+ define do
50
+ on default do
51
+ begin
52
+ page = Proton::Page[env['PATH_INFO']] or break not_found
53
+
54
+ # Make the clients use If-Modified-Since
55
+ res['Cache-Control'] = 'max-age=86400, public, must-revalidate'
56
+
57
+ mtime = [server.options[:last_modified].to_i, File.mtime(page.file).to_i].compact.max
58
+ res['Last-Modified'] = mtime.to_s if mtime
59
+
60
+ # Get the MIME type from Proton, then fallback to Rack
61
+ type = mime_type_for(page)
62
+ res['Content-Type'] = type if type
63
+
64
+ # Okay, we're done
65
+ res.write page.to_html
66
+ show_status page
67
+ rescue => e
68
+ res['Content-Type'] = 'text/html'
69
+ res.write "<h1>#{e.class}: #{e.message}</h1><ul>#{e.backtrace.map{|l|"<li>#{l}</li>"}.join('')}</ul>"
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ module Proton::Server
77
+ # Available options:
78
+ # :last_modified -- timestamp for all files
79
+ def self.options
80
+ @options ||= Hash.new
81
+ end
82
+
83
+ # :Host, :Port
84
+ def self.run!(options={})
85
+ self.options.merge options
86
+ handler = rack_handler or return false
87
+ handler.run self, options
88
+ end
89
+
90
+ def self.rack_handler
91
+ %w(thin mongrel webrick).each do |svr|
92
+ begin
93
+ return Rack::Handler.get(svr)
94
+ rescue LoadError
95
+ rescue NameError
96
+ end
97
+ end
98
+ end
99
+ end
data/lib/proton/set.rb ADDED
@@ -0,0 +1,32 @@
1
+ # Class: Proton::Set
2
+ # A set of pages.
3
+
4
+ class Proton
5
+ class Set < Array
6
+ # Method: find (Proton::Set)
7
+ # Filters a set by given metadata criteria.
8
+ #
9
+ # ## Example
10
+ # Page['/'].children.find(layout: 'default')
11
+ #
12
+ def find(by={})
13
+ self.class.new(select do |page|
14
+ by.inject(true) { |b, (field, value)| b &&= (page.meta.send(field) == value) }
15
+ end)
16
+ end
17
+
18
+ # Method: except (Proton::Set)
19
+ # Filters a set by removing items matching the given metadata criteria.
20
+ #
21
+ # This is the opposite of {Proton::Set::find}.
22
+ #
23
+ # ## Example
24
+ # Page['/'].children.find(layout: 'default')
25
+ #
26
+ def except(by={})
27
+ self.class.new(reject do |page|
28
+ by.inject(true) { |b, (field, value)| b &&= (page.meta.send(field) == value) }
29
+ end)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,13 @@
1
+ class Proton
2
+ VERSION = "0.3.0.rc1"
3
+
4
+ # Attribute: version (Proton)
5
+ # Returns the version.
6
+ #
7
+ # ## Example
8
+ # Proton.version #=> "0.2.0"
9
+
10
+ def self.version
11
+ VERSION
12
+ end
13
+ end
File without changes
@@ -0,0 +1 @@
1
+ div a{color:red}
@@ -0,0 +1,18 @@
1
+ hyde_requirement: 0.1
2
+ site_path: site
3
+ extensions_path: extensions
4
+ output_path: public
5
+ ignore:
6
+ - **/*~
7
+ - **/compass/**/*
8
+ - **/_*.scss
9
+
10
+ tilt_options:
11
+ haml:
12
+ x: 2
13
+ scss:
14
+ :line_numbers: true
15
+
16
+ tilt_build_options:
17
+ scss:
18
+ :line_numbers: false
File without changes
@@ -0,0 +1 @@
1
+ div { a { color: red; } }
@@ -0,0 +1,4 @@
1
+ output_path: public
2
+ site_path: site
3
+ ignore:
4
+ - control
@@ -0,0 +1,5 @@
1
+ @import 'compass/css3';
2
+
3
+ #foo {
4
+ @include border-radius(4px);
5
+ }
File without changes
@@ -0,0 +1 @@
1
+ <h1>hey</h1>
@@ -0,0 +1 @@
1
+ $extension_loaded = 'aoeu'
@@ -0,0 +1 @@
1
+ $hi = 1
@@ -0,0 +1,8 @@
1
+ hyde_requirement: 0.1
2
+ site_path: site
3
+ extensions_path: extensions
4
+ output_path: public
5
+ ignore:
6
+ - **/*~
7
+ - **/compass/**/*
8
+ - **/_*.scss
@@ -0,0 +1 @@
1
+ %h1 hey
@@ -0,0 +1,2 @@
1
+ Parent:
2
+ <a href='/index.html'>Back to parent</a>
@@ -0,0 +1,2 @@
1
+ Parent:
2
+ <a href='/about/index.html'>Back to parent</a>
@@ -0,0 +1 @@
1
+ <h1>Yo</h1>
@@ -0,0 +1,8 @@
1
+ hyde_requirement: 0.1
2
+ site_path: site
3
+ extensions_path: extensions
4
+ output_path: public
5
+ ignore:
6
+ - **/*~
7
+ - **/compass/**/*
8
+ - **/_*.scss
@@ -0,0 +1,4 @@
1
+ title: Hello there
2
+ type: nonexistent
3
+ --
4
+ #ok
@@ -0,0 +1 @@
1
+ hyde_requirement: 9000.0
@@ -0,0 +1 @@
1
+ requirement: 9000.0
@@ -0,0 +1,2 @@
1
+ <h1>Welcome.</h1>
2
+ Hello