ruby_slippers 0.2.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 (51) hide show
  1. data/.rvmrc +2 -0
  2. data/Gemfile +16 -0
  3. data/Gemfile.lock +45 -0
  4. data/Guardfile +16 -0
  5. data/LICENSE +20 -0
  6. data/README.md +122 -0
  7. data/Rakefile +5 -0
  8. data/TODO +32 -0
  9. data/VERSION +1 -0
  10. data/lib/ext/ext.rb +164 -0
  11. data/lib/ruby_slippers.rb +28 -0
  12. data/lib/ruby_slippers/app.rb +47 -0
  13. data/lib/ruby_slippers/archives.rb +22 -0
  14. data/lib/ruby_slippers/article.rb +104 -0
  15. data/lib/ruby_slippers/config.rb +37 -0
  16. data/lib/ruby_slippers/context.rb +38 -0
  17. data/lib/ruby_slippers/engine.rb +21 -0
  18. data/lib/ruby_slippers/repo.rb +21 -0
  19. data/lib/ruby_slippers/site.rb +115 -0
  20. data/lib/ruby_slippers/template.rb +28 -0
  21. data/lib/tasks/gemspec.rake +24 -0
  22. data/lib/tasks/test.rake +17 -0
  23. data/test/fixtures/articles/2010-05-17-the-wonderful-wizard-of-oz.txt +6 -0
  24. data/test/fixtures/articles/2010-05-18-the-marvelous-land-of-oz.txt +7 -0
  25. data/test/fixtures/articles/2010-05-20-dorothy-and-the-wizard-of-oz.txt +6 -0
  26. data/test/fixtures/articles/2011-05-18-ozma-of-oz.txt +10 -0
  27. data/test/fixtures/images/ozma.png +0 -0
  28. data/test/fixtures/pages/about.html.erb +1 -0
  29. data/test/fixtures/pages/archives.html.erb +23 -0
  30. data/test/fixtures/pages/article.html.erb +28 -0
  31. data/test/fixtures/pages/index.html.erb +27 -0
  32. data/test/fixtures/pages/sitemap.html.erb +0 -0
  33. data/test/fixtures/pages/tagged.html.erb +9 -0
  34. data/test/fixtures/templates/index.builder +21 -0
  35. data/test/fixtures/templates/layout.html.erb +4 -0
  36. data/test/fixtures/templates/repo.html.erb +1 -0
  37. data/test/fixtures/templates/sitemap.builder +25 -0
  38. data/test/integration/about_test.rb +23 -0
  39. data/test/integration/archives_test.rb +34 -0
  40. data/test/integration/articles_test.rb +56 -0
  41. data/test/integration/atom_test.rb +24 -0
  42. data/test/integration/invalid_route_test.rb +31 -0
  43. data/test/integration/tags_test.rb +24 -0
  44. data/test/support/test_helper.rb +47 -0
  45. data/test/unit/app_test.rb +14 -0
  46. data/test/unit/archives_test.rb +10 -0
  47. data/test/unit/article_test.rb +145 -0
  48. data/test/unit/date_patch_test.rb +10 -0
  49. data/test/unit/engine_test.rb +71 -0
  50. data/test/unit/site_test.rb +52 -0
  51. metadata +270 -0
data/.rvmrc ADDED
@@ -0,0 +1,2 @@
1
+ rvm_gemset_create_on_use_flag=1
2
+ rvm use 1.9.2@slippers
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rake'
4
+ gem 'rack'
5
+ gem 'hpricot'
6
+ gem 'builder'
7
+ gem 'rdiscount'
8
+ gem 'maruku'
9
+
10
+ group :test, :development do
11
+ gem 'guard'
12
+ gem 'guard-bundler'
13
+ gem 'guard-test'
14
+ gem 'riot'
15
+ gem 'jeweler'
16
+ end
@@ -0,0 +1,45 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ builder (3.0.0)
5
+ git (1.2.5)
6
+ guard (0.4.2)
7
+ thor (~> 0.14.6)
8
+ guard-bundler (0.1.3)
9
+ bundler (>= 1.0.0)
10
+ guard (>= 0.2.2)
11
+ guard-test (0.3.0)
12
+ guard (>= 0.2.2)
13
+ test-unit (~> 2.2)
14
+ hpricot (0.8.4)
15
+ jeweler (1.6.2)
16
+ bundler (~> 1.0)
17
+ git (>= 1.2.5)
18
+ rake
19
+ maruku (0.6.0)
20
+ syntax (>= 1.0.0)
21
+ rack (1.3.0)
22
+ rake (0.9.2)
23
+ rdiscount (1.6.8)
24
+ riot (0.12.4)
25
+ rr
26
+ rr (1.0.2)
27
+ syntax (1.0.0)
28
+ test-unit (2.3.0)
29
+ thor (0.14.6)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ builder
36
+ guard
37
+ guard-bundler
38
+ guard-test
39
+ hpricot
40
+ jeweler
41
+ maruku
42
+ rack
43
+ rake
44
+ rdiscount
45
+ riot
@@ -0,0 +1,16 @@
1
+ guard 'bundler' do
2
+ watch('Gemfile')
3
+ watch('Gemfile.lock')
4
+ end
5
+
6
+ guard 'test' do
7
+ watch(%r{^test/fixtures/articles/(.+)\.txt$})
8
+ watch(%r{^test/fixtures/templates/(.+)$})
9
+ watch(%r{^test/fixtures/pages/(.+)$})
10
+
11
+ watch(%r{^lib/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
12
+ watch(%r{^lib/ruby_slippers/(.+)\.rb$}) { |m| ["test/unit/#{m[1]}_test.rb", "test/integration/#{m[1]}_test.rb"] }
13
+ watch(%r{^test/integration/.+_test\.rb$})
14
+ watch(%r{^test/unit/.+_test\.rb$})
15
+ watch(%r{^test/support/(.+)\.rb$}) { "test" }
16
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 dreamr
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,122 @@
1
+ README
2
+ ======
3
+
4
+ RubySlippers, the smartest blogging engine in all of Oz!
5
+ --------------------------------------------------------
6
+
7
+ [website](http://ruby-slippers.heroku.com)
8
+
9
+ Introduction
10
+ ------------
11
+
12
+ ### To set up a new blog
13
+
14
+ $ git clone git://github.com/dreamr/ruby-slippers.git myblog
15
+ $ cd myblog
16
+ $ gem install bundler
17
+ $ bundle
18
+ $ rake install
19
+ $ -> Blog name: My new blog
20
+ $ Installing your blog to my-new-blog
21
+ $ Blog installed!
22
+
23
+
24
+ ### To create an article
25
+
26
+ $ rake new
27
+ $ -> Title: My new blog post!
28
+ $ Creating and opening my-new-blog-post (opens in your text editor!)
29
+ $ rake publish (commits, pushes, publishes then opens in your browser!)
30
+
31
+
32
+ Philosophy
33
+ ----------
34
+
35
+ RubySlippers is based on [Toto](http://github.com/cloudhead/toto) and aims to achieve their goals as well as our own. Hosting a ruby based free blog shouldn't be hard. We want to take that a step further and say it should be easy. Easy as pie. Easy as my best friend's Mom. Easy as a 1 click installer.
36
+
37
+ Oh yeah, MRI, bytecode whatever. If it is Ruby, it should run.
38
+
39
+ How it works
40
+ ------------
41
+
42
+ - Article management is done with a text editor and git
43
+ * stored as _.txt_ files, with embeded metadata (in yaml format).
44
+ * processed through a markdown converter (rdiscount) by default.
45
+ * can have tags
46
+ * can have images
47
+ * can be browsed by date, or tags
48
+ * comments are handled by [disqus](http://disqus.com)
49
+ - built for easy use with _ERB_.
50
+ - built right on top of _Rack_.
51
+ - built to take advantage of _HTTP caching_.
52
+ - built with _heroku_ in mind.
53
+
54
+
55
+ RubySlippers comes with a basic default theme for you to mangle. I hope to release more themes shortly and will accept your submitted themes.
56
+
57
+ Deployment
58
+ ==========
59
+
60
+ #### On heroku
61
+
62
+ $ git add .
63
+ $ git commit -m 'updated blog'
64
+ $ git push heroku
65
+
66
+ #### On your own server or locally
67
+
68
+ Once you have created the remote git repo, and pushed your changes to it, you can run RubySlippers with any Rack compliant web server, such as **thin**, **mongrel** or **unicorn**.
69
+
70
+ I like to use shotgun as it reloads while I work
71
+
72
+ $ cd myblog
73
+ $ bundle
74
+ $ shotgun
75
+
76
+ With thin, you would do something like:
77
+
78
+ $ thin start -R config.ru
79
+
80
+ With unicorn, you can just do:
81
+
82
+ $ unicorn
83
+
84
+
85
+ ### Configuration
86
+
87
+ You can configure ruby-slippers, by modifying the _config.ru_ file. For example, if you want to set the blog author to 'John Galt',
88
+ you could add `set :author, 'John Galt'` inside the `RubySlippers::Engine::App.new` block. Here are the defaults, to get you started:
89
+
90
+ #
91
+ # Add your settings here
92
+ # set [:setting], [value]
93
+ #
94
+ set :author, "Dreamr" # blog author
95
+ set :title, "RubySlippers, the smartest blog engine in all of Oz!" # site title
96
+ # set :root, "index" # page to load on /
97
+ set :date, lambda {|now| now.strftime("%m/%d/%Y") } # date format for articles
98
+ # set :markdown, :smart # use markdown + smart-mode
99
+ # set :disqus, false # disqus id, or false
100
+ set :summary, :max => 300, :delim => /~/ # length of article summary and delimiter
101
+ # set :ext, 'txt' # file extension for articles
102
+ # set :cache, 28800 # cache duration, in seconds
103
+ set :tag_separator, ', ' # tag separator for articles
104
+ set :date, lambda {|now| now.strftime("%B #{now.day.ordinal} %Y") }
105
+ # set this to your local port. I use shotgun, so 9393.
106
+ set :url, "http://localhost:9393" if ENV['RACK_ENV'] == 'development'
107
+
108
+ # to use haml, add the gem to your Gemfile and bundle, then uncomment this
109
+ # and redo your templates using haml and renamed to html.haml
110
+ # set :to_html, lambda { |path, page, binding|
111
+ # Haml::Engine.new(File.read("#{path}/#{page}.html.haml"),
112
+ # :attr_wrapper => '"',
113
+ # :filename => path ).render(binding)
114
+ # }
115
+
116
+ Thanks
117
+ ------
118
+
119
+ * To heroku for making this easy as pie.
120
+ * To the developers of [Toto](http://github.com/cloudhead/toto), for making such an awesome minimal blog engine in Ruby.
121
+
122
+ Copyright (c) 2011 dreamr. See LICENSE for details.
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ Dir.glob('lib/tasks/*.rake').each { |file| import file }
4
+
5
+ task :default => 'test:all'
data/TODO ADDED
@@ -0,0 +1,32 @@
1
+ TODO
2
+ ====
3
+
4
+ Site features
5
+ -------------
6
+ Contact form (email)
7
+ * reverse captcha
8
+ * must be free service
9
+
10
+
11
+ Blog features
12
+ -----------------------------
13
+
14
+ * Most popular posts (hits)
15
+ * Most commented posts (comments)
16
+ * Related posts (by tag)
17
+
18
+
19
+
20
+ Full stack test/deployment scheme
21
+ -------------------------------------------
22
+
23
+ * Engine
24
+ [*] Unit Tests
25
+ [*] Integration Tests
26
+
27
+ * Staged (deployed)
28
+ [*] Integration Tests
29
+ [ ] Client Rake Tests
30
+
31
+
32
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,164 @@
1
+ require 'enumerator'
2
+
3
+ class Array
4
+ # Splits or iterates over the array in groups of size +number+,
5
+ # padding any remaining slots with +fill_with+ unless it is +false+.
6
+ #
7
+ # %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group}
8
+ # ["1", "2", "3"]
9
+ # ["4", "5", "6"]
10
+ # ["7", nil, nil]
11
+ #
12
+ # %w(1 2 3).in_groups_of(2, ' ') {|group| p group}
13
+ # ["1", "2"]
14
+ # ["3", " "]
15
+ #
16
+ # %w(1 2 3).in_groups_of(2, false) {|group| p group}
17
+ # ["1", "2"]
18
+ # ["3"]
19
+ def in_groups_of(number, fill_with = nil)
20
+ if fill_with == false
21
+ collection = self
22
+ else
23
+ # size % number gives how many extra we have;
24
+ # subtracting from number gives how many to add;
25
+ # modulo number ensures we don't add group of just fill.
26
+ padding = (number - size % number) % number
27
+ collection = dup.concat([fill_with] * padding)
28
+ end
29
+
30
+ if block_given?
31
+ collection.each_slice(number) { |slice| yield(slice) }
32
+ else
33
+ groups = []
34
+ collection.each_slice(number) { |group| groups << group }
35
+ groups
36
+ end
37
+ end
38
+
39
+ # Splits or iterates over the array in +number+ of groups, padding any
40
+ # remaining slots with +fill_with+ unless it is +false+.
41
+ #
42
+ # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group}
43
+ # ["1", "2", "3", "4"]
44
+ # ["5", "6", "7", nil]
45
+ # ["8", "9", "10", nil]
46
+ #
47
+ # %w(1 2 3 4 5 6 7).in_groups(3, '&nbsp;') {|group| p group}
48
+ # ["1", "2", "3"]
49
+ # ["4", "5", "&nbsp;"]
50
+ # ["6", "7", "&nbsp;"]
51
+ #
52
+ # %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
53
+ # ["1", "2", "3"]
54
+ # ["4", "5"]
55
+ # ["6", "7"]
56
+ def in_groups(number, fill_with = nil)
57
+ # size / number gives minor group size;
58
+ # size % number gives how many objects need extra accommodation;
59
+ # each group hold either division or division + 1 items.
60
+ division = size / number
61
+ modulo = size % number
62
+
63
+ # create a new array avoiding dup
64
+ groups = []
65
+ start = 0
66
+
67
+ number.times do |index|
68
+ length = division + (modulo > 0 && modulo > index ? 1 : 0)
69
+ padding = fill_with != false &&
70
+ modulo > 0 && length == division ? 1 : 0
71
+ groups << slice(start, length).concat([fill_with] * padding)
72
+ start += length
73
+ end
74
+
75
+ if block_given?
76
+ groups.each { |g| yield(g) }
77
+ else
78
+ groups
79
+ end
80
+ end
81
+
82
+ # Divides the array into one or more subarrays based on a delimiting +value+
83
+ # or the result of an optional block.
84
+ #
85
+ # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
86
+ # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
87
+ def split(value = nil)
88
+ using_block = block_given?
89
+
90
+ inject([[]]) do |results, element|
91
+ if (using_block && yield(element)) || (value == element)
92
+ results << []
93
+ else
94
+ results.last << element
95
+ end
96
+
97
+ results
98
+ end
99
+ end
100
+ end
101
+
102
+ class Object
103
+ def meta_def name, &blk
104
+ (class << self; self; end).instance_eval do
105
+ define_method(name, &blk)
106
+ end
107
+ end
108
+ end
109
+
110
+ class String
111
+ def slugize
112
+ self.downcase.gsub(/&/, 'and').gsub(/\s+/, '-').gsub(/[^a-z0-9-]/, '')
113
+ end
114
+
115
+ def humanize
116
+ self.capitalize.gsub(/[-_]+/, ' ')
117
+ end
118
+ end
119
+
120
+ class Fixnum
121
+ def ordinal
122
+ # 1 => 1st
123
+ # 2 => 2nd
124
+ # 3 => 3rd
125
+ # ...
126
+ case self % 100
127
+ when 11..13; "#{self}th"
128
+ else
129
+ case self % 10
130
+ when 1; "#{self}st"
131
+ when 2; "#{self}nd"
132
+ when 3; "#{self}rd"
133
+ else "#{self}th"
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ class Object
140
+ def blank?
141
+ self.nil? || self == ""
142
+ end
143
+ end
144
+
145
+ class Date
146
+ # This check is for people running RubySlippers::Enginewith ActiveSupport, avoid a collision
147
+ unless respond_to? :iso8601
148
+ # Return the date as a String formatted according to ISO 8601.
149
+ def iso8601
150
+ ::Time.utc(year, month, day, 0, 0, 0, 0).iso8601
151
+ end
152
+ end
153
+ end
154
+
155
+ module Kernel
156
+ def silence_stream(stream)
157
+ old_stream = stream.dup
158
+ stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
159
+ stream.sync = true
160
+ yield
161
+ ensure
162
+ stream.reopen(old_stream)
163
+ end
164
+ end
@@ -0,0 +1,28 @@
1
+ require 'yaml'
2
+ require 'date'
3
+ require 'erb'
4
+ require 'rack'
5
+ require 'digest'
6
+ require 'open-uri'
7
+
8
+ if RUBY_PLATFORM =~ /win32/
9
+ require 'maruku'
10
+ Markdown = Maruku
11
+ else
12
+ require 'rdiscount'
13
+ end
14
+
15
+ require 'builder'
16
+
17
+ $:.unshift File.dirname(__FILE__)
18
+
19
+ require 'ext/ext'
20
+ require 'ruby_slippers/app'
21
+ require 'ruby_slippers/site'
22
+ require 'ruby_slippers/engine'
23
+ require 'ruby_slippers/config'
24
+ require 'ruby_slippers/template'
25
+ require 'ruby_slippers/context'
26
+ require 'ruby_slippers/article'
27
+ require 'ruby_slippers/archives'
28
+ require 'ruby_slippers/repo'