proton 0.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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