days 0.2.0 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +21 -4
  3. data/app/javascripts/admin/bootstrap.min.js +7 -0
  4. data/app/javascripts/jquery-2.1.3.min.js +4 -0
  5. data/app/stylesheets/admin/bootstrap-theme.min.css +5 -0
  6. data/app/stylesheets/admin/bootstrap.min.css +5 -0
  7. data/app/stylesheets/admin/login.scss +3 -5
  8. data/app/stylesheets/admin.scss +4 -0
  9. data/app/views/admin/categories.haml +3 -3
  10. data/app/views/admin/entries/form.haml +22 -17
  11. data/app/views/admin/entries/index.haml +46 -28
  12. data/app/views/admin/login.haml +11 -8
  13. data/app/views/admin/setup.haml +16 -9
  14. data/app/views/admin.haml +31 -21
  15. data/days.gemspec +14 -11
  16. data/lib/days/app/admin/entries.rb +11 -5
  17. data/lib/days/app/entries.rb +24 -13
  18. data/lib/days/app.rb +2 -3
  19. data/lib/days/command.rb +1 -1
  20. data/lib/days/config.rb +18 -5
  21. data/lib/days/helpers.rb +13 -11
  22. data/lib/days/models/base.rb +11 -0
  23. data/lib/days/models/category.rb +2 -2
  24. data/lib/days/models/entry.rb +41 -8
  25. data/lib/days/models/user.rb +2 -2
  26. data/lib/days/version.rb +1 -1
  27. data/scripts/tumblr_export.rb +1 -1
  28. data/spec/controllers/admin/categories_spec.rb +22 -22
  29. data/spec/controllers/admin/entries_spec.rb +155 -44
  30. data/spec/controllers/admin/session_spec.rb +16 -25
  31. data/spec/controllers/admin/setup_spec.rb +22 -25
  32. data/spec/controllers/admin/users_spec.rb +39 -40
  33. data/spec/controllers/entries_spec.rb +71 -42
  34. data/spec/helpers_spec.rb +18 -29
  35. data/spec/models/entry_spec.rb +117 -47
  36. data/spec/shared/admin.rb +2 -2
  37. data/spec/spec_helper.rb +25 -25
  38. metadata +111 -86
  39. data/app/javascripts/bootstrap.js +0 -2159
  40. data/app/javascripts/bootstrap.min.js +0 -6
  41. data/app/javascripts/jquery-1.8.3.min.js +0 -2
  42. data/app/stylesheets/bootstrap-responsive.css +0 -1092
  43. data/app/stylesheets/bootstrap-responsive.min.css +0 -9
  44. data/app/stylesheets/bootstrap.css +0 -6039
  45. data/app/stylesheets/bootstrap.min.css +0 -9
data/app/views/admin.haml CHANGED
@@ -3,35 +3,45 @@
3
3
  %head
4
4
  %meta{charset: 'UTF-8'}
5
5
  %meta{name: "viewport", content: "width=device-width, initial-scale=1.0"}
6
- %link{href: "/assets/bootstrap.min.css", rel: "stylesheet"}
6
+ %link{href: "/assets/admin/bootstrap.min.css", rel: "stylesheet"}
7
7
  %link{href: "/assets/admin.css", rel: "stylesheet", media: "screen"}
8
- %link{href: "/assets/bootstrap-responsive.min.css", rel: "stylesheet"}
9
- %script{src: '/assets/jquery-1.8.3.min.js'}
10
- %script{src: '/assets/bootstrap.min.js'}
8
+ %script{src: '/assets/jquery-2.1.3.min.js'}
9
+ %script{src: '/assets/admin/bootstrap.min.js'}
11
10
  - if @title
12
11
  %title #{@title} - Days Admin
13
12
  - else
14
13
  %title Days Admin
15
14
  %body
16
- .navbar.navbar-inverse.navbar-fixed-top
17
- .navbar-inner
18
- .container
19
- %a.btn.btn-navbar{data: {toggle: 'collapse', target: '.nav-collapse'}}
15
+ %nav.navbar.navbar-default.navbar-fixed-top
16
+ .container
17
+ .navbar-header
18
+ %button.navbar-toggle.collapsed{type: 'button', data: {toggle: 'collapse', target: '#navbar-collapse-1'}}
19
+ %span.sr-only Toggle navigation
20
20
  %span.icon-bar
21
21
  %span.icon-bar
22
22
  %span.icon-bar
23
- %a.brand{href: '/admin/'} Days
24
- %form.navbar-form.pull-right{action: "/admin/logout", method: "POST"}
25
- != csrf_tag
26
- %button.btn.btn-link{type: 'submit'} Log out
27
- %a.btn.btn-primary{href: '/admin/entries/new'} New Entry
28
23
 
29
- %div.nav-collapse.collapse
30
- %ul.nav
31
- %li
32
- %a{href: '/admin/entries'} Entries
33
- %li
34
- %a{href: '/admin/categories'} Categories
35
- %li
36
- %a{href: '/admin/users'} Users
24
+ %a.navbar-brand{href: '/admin/'} Days
25
+
26
+ %form.navbar-form.navbar-right.hidden-xs{action: "/admin/logout", method: "POST"}
27
+ != csrf_tag
28
+ %button.btn.btn-link{type: 'submit'} Log out
29
+ %a.btn.btn-default{href: '/admin/entries/new'} New Entry
30
+
31
+ %div.collapse.navbar-collapse#navbar-collapse-1
32
+ %ul.nav.navbar-nav
33
+ %li.visible-xs
34
+ %form
35
+ %a.btn.btn-default.visible-xs{href: '/admin/entries/new'} New Entry
36
+ %li
37
+ %a{href: '/admin/entries'} Entries
38
+ %li
39
+ %a{href: '/admin/categories'} Categories
40
+ %li
41
+ %a{href: '/admin/users'} Users
42
+ %li.visible-xs
43
+ %form.form-inline{action: "/admin/logout", method: "POST"}
44
+ != csrf_tag
45
+ %button.btn.btn-link{type: 'submit'} Log out
46
+
37
47
  != yield
data/days.gemspec CHANGED
@@ -17,31 +17,34 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
 
20
- gem.add_dependency "sinatra", '~> 1.3.3'
20
+ gem.add_dependency "sinatra", '>= 1.4.5'
21
21
  gem.add_dependency "thor", '~> 0.16.0'
22
- gem.add_dependency "rack_csrf", '~> 2.4.0'
22
+ gem.add_dependency "rack_csrf", '~> 2.5.0'
23
23
 
24
24
  gem.add_dependency "settingslogic", '~> 2.0.9'
25
25
 
26
- gem.add_dependency "sprockets", '~> 2.2.2'
27
- gem.add_dependency "haml", '~> 3.1.7'
26
+ gem.add_dependency "sprockets", '~> 2.12.3'
27
+ gem.add_dependency "faml", '>= 0.2.4'
28
28
  gem.add_dependency "sass", '~> 3.2.5'
29
29
 
30
- gem.add_dependency "redcarpet", '~> 2.2.2'
31
- gem.add_dependency "builder", '~> 3.0.0'
30
+ gem.add_dependency "builder", '~> 3.1'
32
31
 
33
- gem.add_dependency "activerecord", "~> 3.2.14"
34
- gem.add_dependency "kaminari", "~> 0.13"
32
+ gem.add_dependency "activerecord", "~> 4.2.0"
33
+ gem.add_dependency "protected_attributes"
34
+ gem.add_dependency "kaminari", "~> 0.16.1"
35
35
  gem.add_dependency "padrino-helpers", '~> 0.9.21'
36
36
  gem.add_dependency "stringex", '~> 1.5.1'
37
- gem.add_dependency "bcrypt-ruby", '~> 3.0.1'
37
+ gem.add_dependency "bcrypt", '~> 3.1.9'
38
+
39
+ gem.add_dependency "html-pipeline", '>= 1.11.0'
40
+ gem.add_dependency "github-markdown"
38
41
 
39
42
  gem.add_development_dependency "sqlite3"
40
43
 
41
- gem.add_development_dependency "rspec"
44
+ gem.add_development_dependency "rspec", '~> 3.2.0'
42
45
  gem.add_development_dependency "rack-test"
43
46
  gem.add_development_dependency "fuubar"
47
+ gem.add_development_dependency "database_rewinder"
44
48
 
45
49
  gem.add_dependency "pry"
46
- gem.add_development_dependency "pry-nav"
47
50
  end
@@ -1,7 +1,11 @@
1
1
  module Days
2
2
  class App < Sinatra::Base
3
3
  get "/admin/entries", :admin_only => true do
4
- @entries = Entry.order('id DESC').all
4
+ @entries = Entry.order(id: :desc)
5
+ @entries = @entries.draft if params[:draft] && !params[:draft].empty?
6
+ @entries = @entries.scheduled if params[:scheduled] && !params[:scheduled].empty?
7
+ @entries = @entries.published if params[:published] && !params[:published].empty?
8
+ @entries = @entries.page(params[:page] || 1)
5
9
  haml :'admin/entries/index', layout: :admin
6
10
  end
7
11
 
@@ -22,6 +26,7 @@ module Days
22
26
 
23
27
  @entry = Entry.new(entry)
24
28
  @entry.user = current_user
29
+ @entry.pipeline = config.html_pipeline if config.html_pipeline
25
30
 
26
31
  if @entry.save
27
32
  redirect "/admin/entries/#{@entry.id}" # FIXME: Permalink
@@ -36,19 +41,20 @@ module Days
36
41
  end
37
42
 
38
43
  get "/admin/entries/:id", :admin_only => true do
39
- @entry = Entry.where(id: params[:id]).first || halt(404)
44
+ @entry = Entry.find_by(id: params[:id]) || halt(404)
40
45
  @categories = Category.all
41
46
  haml :'admin/entries/form', layout: :admin
42
47
  end
43
48
 
44
49
  put "/admin/entries/:id", :admin_only => true do
45
50
  entry = params[:entry] || halt(400)
46
- @entry = Entry.where(id: params[:id]).first || halt(404)
51
+ @entry = Entry.find_by(id: params[:id]) || halt(404)
52
+ @entry.pipeline = config.html_pipeline if config.html_pipeline
47
53
 
48
54
  entry[:categories] = Category.where(
49
55
  id: (entry[:categories] || {}).keys.map(&:to_i)
50
56
  )
51
- @entry.update_attributes(entry)
57
+ @entry.assign_attributes(entry)
52
58
 
53
59
  if @entry.save
54
60
  redirect "/admin/entries/#{@entry.id}"
@@ -60,7 +66,7 @@ module Days
60
66
  end
61
67
 
62
68
  delete "/admin/entries/:id", :admin_only => true do
63
- @entry = Entry.where(id: params[:id]).first || halt(404)
69
+ @entry = Entry.find_by(id: params[:id]) || halt(404)
64
70
  @entry.destroy
65
71
 
66
72
  redirect "/admin/entries"
@@ -20,7 +20,7 @@ module Days
20
20
  end
21
21
  end
22
22
 
23
- entry = Entry.where(old_path: request.path).first
23
+ entry = Entry.find_by(old_path: request.path)
24
24
  if entry
25
25
  return [301, {'Location' => entry_path(entry)}, ""]
26
26
  end
@@ -32,7 +32,7 @@ module Days
32
32
  end
33
33
 
34
34
  get '/category/:name' do
35
- category = Category.where(name: params[:name]).first || halt(404)
35
+ category = Category.find_by(name: params[:name]) || halt(404)
36
36
  @entries = category.entries.published.page(params[:page] || 1)
37
37
  haml :entries
38
38
  end
@@ -50,20 +50,15 @@ module Days
50
50
  haml :entries
51
51
  end
52
52
 
53
- get '/feed' do
54
- content_type 'application/atom+xml'
55
- entries = Entry.published.first(50)
56
-
53
+ private def generate_atom_feed(entries, title: config.title, html_path: '/feed')
57
54
  xml = Builder::XmlMarkup.new
58
-
59
55
  xml.instruct!
60
-
61
56
  xml.feed("xmlns" => 'http://www.w3.org/2005/Atom') do
62
57
  xml.id("tag:#{request.host},2005:#{request.fullpath.split(".")[0]}")
63
58
 
64
- xml.link(:rel => 'alternate', :type => 'text/html', :href => request.url.gsub(/feed$/,''))
59
+ xml.link(:rel => 'alternate', :type => 'text/html', :href => [request.base_url, config.base_path, html_path].join.gsub(%r{//}, '/'))
65
60
  xml.link(:rel => 'self', :type => 'application/atom+xml', :href => request.url)
66
- xml.title config.title
61
+ xml.title title
67
62
 
68
63
  xml.updated(entries.map(&:updated_at).max)
69
64
 
@@ -74,14 +69,30 @@ module Days
74
69
  xml.published entry.published_at.xmlschema
75
70
  xml.updated entry.updated_at.xmlschema
76
71
 
77
- xml.link(rel: 'alternate', type: 'text/html', href: "#{request.url.gsub(/\/feed$/,'')}#{entry_path(entry)}")
78
-
79
72
  xml.title entry.title
80
73
 
81
- xml.content(entry.short_rendered { '... <a href="'+entry_path(entry)+'">Continue Reading</a>' }, type: 'html')
74
+ href = [request.base_url, config.base_path, entry_path(entry)].join.gsub(%r{//}, '/')
75
+ xml.link(rel: 'alternate', type: 'text/html', href: href)
76
+ xml.content(entry.short_rendered { '... <a href="'+href+'">Continue Reading</a>' }, type: 'html')
82
77
  end
83
78
  end
84
79
  end
85
80
  end
81
+
82
+ get '/feed' do
83
+ entries = Entry.published.page(params[:page])
84
+
85
+ content_type 'application/atom+xml'
86
+ generate_atom_feed(entries)
87
+ end
88
+
89
+ get '/feed/category/:name' do
90
+ category = Category.find_by(name: params[:name]) || halt(404)
91
+ entries = category.entries.published.page(params[:page])
92
+
93
+ content_type 'application/atom+xml'
94
+ generate_atom_feed(entries, title: "#{config.title} (Category: #{category.name})", html_path: "/category/#{category.name}")
95
+ end
96
+
86
97
  end
87
98
  end
data/lib/days/app.rb CHANGED
@@ -5,7 +5,7 @@ require 'rack/csrf'
5
5
  require_relative 'config'
6
6
  require_relative 'models'
7
7
  require_relative 'helpers'
8
- require 'haml'
8
+ require 'faml'
9
9
  require 'sass'
10
10
 
11
11
  I18n.load_path.reject! {|_| _.match(/padrino/) }
@@ -48,8 +48,6 @@ module Days
48
48
  set(:config, nil)
49
49
  set :method_override, true
50
50
 
51
- set :haml, :escape_html => true
52
-
53
51
  helpers Helpers
54
52
  helpers Kaminari::Helpers::SinatraHelpers
55
53
 
@@ -106,6 +104,7 @@ module Days
106
104
  env.append_path "#{self.root}/images"
107
105
  })
108
106
  config.establish_db_connection()
107
+ config.run_scripts()
109
108
  x
110
109
  end
111
110
  end
data/lib/days/command.rb CHANGED
@@ -55,7 +55,7 @@ module Days
55
55
  desc "server", "Starts the server"
56
56
  method_option :config, :type => :string, :aliases => "-c"
57
57
  method_option :port, :type => :numeric, :aliases => "-p", :default => 3162
58
- method_option :bind, :type => :string, :aliases => "-b", :default => nil
58
+ method_option :bind, :type => :string, :aliases => "-b", :default => 'localhost'
59
59
  method_option :environment, :type => :string, :aliases => "-e", :default => "development"
60
60
  method_option :pid, :type => :string, :aliases => "-c"
61
61
  def server
data/lib/days/config.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require_relative 'app'
2
- require 'active_record'
2
+ require 'days/models/base'
3
+ require 'html/pipeline'
3
4
  require 'logger'
4
5
  require 'settingslogic'
5
6
 
@@ -33,17 +34,29 @@ module Days
33
34
  end
34
35
  end
35
36
 
37
+ attr_accessor :html_pipeline
36
38
 
37
- def establish_db_connection(force=false)
39
+ def run_scripts
40
+ instance_eval (self[:script_lines] || []).join("\n")
41
+
42
+ (self[:scripts] || []).each do |_|
43
+ path = File.expand_path(_, self[:root])
44
+ instance_eval File.read(path), path, 1
45
+ end
46
+ end
47
+
48
+ def establish_db_connection(force=false, base: ActiveRecord::Base)
38
49
  if Days::App.environment.to_sym == :development && (self.has_key?(:activerecord_log) ? self.activerecord_log == true : true)
39
- ActiveRecord::Base.logger = Logger.new($stdout)
50
+ base.logger = Logger.new($stdout)
40
51
  end
41
52
 
53
+ base.default_timezone = self['database_timezone'] ? self['database_timezone'].to_sym : :local
54
+
42
55
  begin
43
56
  raise ActiveRecord::ConnectionNotEstablished if force
44
- return ActiveRecord::Base.connection
57
+ return base.connection
45
58
  rescue ActiveRecord::ConnectionNotEstablished
46
- ActiveRecord::Base.establish_connection(self['database'] ? Hash[self.database] : ENV["DATABASE_URL"])
59
+ base.establish_connection(self['database'] ? Hash[self.database] : ENV["DATABASE_URL"])
47
60
  retry
48
61
  end
49
62
  end
data/lib/days/helpers.rb CHANGED
@@ -38,8 +38,12 @@ module Days
38
38
  config.permalink.gsub(/{(\w+?)}/) { hash[$1.to_sym] }
39
39
  end
40
40
 
41
+ def self.lookup_entry_regexp_for(permalink_format)
42
+ (@lookup_entry_regexp_cache ||= {})[permalink_format] ||= Regexp.compile(Regexp.escape(permalink_format).gsub(/\\{(\w+?)\\}/) { "(?<#{$1}>.+?)" } + "$")
43
+ end
44
+
41
45
  def lookup_entry(path)
42
- regexp = Regexp.compile(Regexp.escape(config.permalink).gsub(/\\{(\w+?)\\}/) { "(?<#{$1}>.+?)" } + "$")
46
+ regexp = Helpers.lookup_entry_regexp_for(config.permalink)
43
47
  m = regexp.match(path)
44
48
  return nil unless m
45
49
 
@@ -48,27 +52,25 @@ module Days
48
52
  hash
49
53
  end
50
54
 
51
-
52
55
  if match[:id] || match[:slug]
53
56
  if match[:id]
54
- query = Entry.where(id: match[:id])
57
+ entry = Entry.find(match[:id])
55
58
  else
56
- query = Entry.where(slug: match[:slug])
59
+ entry = Entry.find_by(slug: match[:slug])
57
60
  end
58
61
 
59
- entry = query.first
60
62
  return nil unless entry
61
63
  published_at = entry.published_at
62
64
  return nil unless published_at
63
65
 
64
66
  return nil if match[:slug] && match[:slug] != entry.slug
65
67
  return nil if match[:id] && match[:id].to_i != entry.id
66
- return nil if match[:year] && match[:year].to_i != published_at.year
67
- return nil if match[:month] && match[:month].to_i != published_at.month
68
- return nil if match[:day] && match[:day].to_i != published_at.day
69
- return nil if match[:hour] && match[:hour].to_i != published_at.hour
70
- return nil if match[:minute] && match[:minute].to_i != published_at.min
71
- return nil if match[:second] && match[:second].to_i != published_at.sec
68
+ return nil if match[:year] && match[:year].to_i != published_at.localtime.year
69
+ return nil if match[:month] && match[:month].to_i != published_at.localtime.month
70
+ return nil if match[:day] && match[:day].to_i != published_at.localtime.day
71
+ return nil if match[:hour] && match[:hour].to_i != published_at.localtime.hour
72
+ return nil if match[:minute] && match[:minute].to_i != published_at.localtime.min
73
+ return nil if match[:second] && match[:second].to_i != published_at.localtime.sec
72
74
 
73
75
  return entry
74
76
  else
@@ -0,0 +1,11 @@
1
+ require 'active_record'
2
+ require 'protected_attributes'
3
+ require 'active_record/mass_assignment_security'
4
+
5
+ module Days
6
+ module Models
7
+ class Base < ActiveRecord::Base
8
+ self.abstract_class = true
9
+ end
10
+ end
11
+ end
@@ -1,7 +1,7 @@
1
- require 'active_record'
1
+ require 'days/models/base'
2
2
 
3
3
  module Days
4
- class Category < ActiveRecord::Base
4
+ class Category < Days::Models::Base
5
5
  attr_accessible :name
6
6
 
7
7
  validates_presence_of :name
@@ -1,9 +1,9 @@
1
- require 'active_record'
1
+ require 'days/models/base'
2
+ require 'html/pipeline'
2
3
  require 'stringex'
3
- require 'redcarpet'
4
4
 
5
5
  module Days
6
- class Entry < ActiveRecord::Base
6
+ class Entry < Days::Models::Base
7
7
  attr_accessible :title, :body, :slug, :published_at, :categories, :user, :draft, :old_path
8
8
 
9
9
  validates_uniqueness_of :slug
@@ -18,6 +18,16 @@ module Days
18
18
  order('published_at DESC')
19
19
  end
20
20
 
21
+ scope :draft, -> do
22
+ where(published_at: nil)
23
+ end
24
+
25
+ scope :scheduled, -> do
26
+ includes(:categories).
27
+ where('published_at IS NOT NULL AND published_at >= ?', Time.now).
28
+ order('published_at DESC')
29
+ end
30
+
21
31
  paginates_per 12
22
32
 
23
33
  def draft=(x)
@@ -45,6 +55,32 @@ module Days
45
55
  self.rendered.gsub(/<!-- *more *-->.+\z/m, block_given? ? yield(self) : '')
46
56
  end
47
57
 
58
+ def body=(*)
59
+ @need_rendering = true
60
+ super
61
+ end
62
+
63
+ def self.default_pipeline
64
+ HTML::Pipeline.new([
65
+ HTML::Pipeline::MarkdownFilter,
66
+ ])
67
+ end
68
+
69
+ def pipeline=(other)
70
+ @pipeline = other
71
+ end
72
+
73
+ def pipeline
74
+ @pipeline ||= self.class.default_pipeline
75
+ end
76
+
77
+ def render!(pipeline: self.pipeline)
78
+ result = pipeline.call(self.body)
79
+ self.rendered = result[:output].to_s
80
+ @need_rendering = false
81
+ nil
82
+ end
83
+
48
84
  before_validation do
49
85
  if draft?
50
86
  self.published_at = nil
@@ -55,11 +91,8 @@ module Days
55
91
  if self.title && (!self.slug || self.slug.empty?)
56
92
  self.slug = self.title.to_url
57
93
  end
58
- markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML,
59
- :autolink => true, :space_after_headers => true,
60
- :no_intra_emphasis => true, :fenced_code_blocks => true,
61
- :tables => true, :superscript => true)
62
- self.rendered = markdown.render(self.body)
94
+
95
+ self.render! if @need_rendering
63
96
  end
64
97
  end
65
98
  end
@@ -1,7 +1,7 @@
1
- require 'active_record'
1
+ require 'days/models/base'
2
2
 
3
3
  module Days
4
- class User < ActiveRecord::Base
4
+ class User < Days::Models::Base
5
5
  has_secure_password
6
6
 
7
7
  attr_accessible :login_name, :name, :password, :password_confirmation
data/lib/days/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Days
2
- VERSION = "0.2.0"
2
+ VERSION = "1.0.0.rc1"
3
3
  end
@@ -71,7 +71,7 @@ loop do
71
71
  <div class="t-photos-caption">
72
72
  #{post['caption']}
73
73
  </div>
74
- </div>
74
+ </section>
75
75
  EOF
76
76
  when 'quote'
77
77
  entry[:title] = post['text'] ? post['text'].dup : ''
@@ -2,9 +2,8 @@ require 'spec_helper'
2
2
 
3
3
  describe Days::App, type: :controller do
4
4
  describe "admin: categories" do
5
- fixtures :users, :categories
6
- let(:user) { users(:blogger) }
7
- let(:category) { categories(:daily) }
5
+ let(:user) { Days::User.create!(login_name: 'blogger', name: 'blogger', password: 'x', password_confirmation: 'x') }
6
+ let!(:category) { Days::Category.create!(name: 'daily') }
8
7
 
9
8
  before { login(user) }
10
9
 
@@ -13,13 +12,13 @@ describe Days::App, type: :controller do
13
12
 
14
13
  it_behaves_like 'an admin page'
15
14
 
16
- it { should be_ok }
15
+ it { is_expected.to be_ok }
17
16
 
18
17
  it "lists up categories" do
19
- render[:data].should == :'admin/categories'
18
+ expect(render[:data]).to eq(:'admin/categories')
20
19
 
21
20
  categories = render[:ivars][:@categories]
22
- categories.should == Days::Category.all
21
+ expect(categories.to_a).to eq([category])
23
22
  end
24
23
  end
25
24
 
@@ -30,20 +29,21 @@ describe Days::App, type: :controller do
30
29
  it_behaves_like 'an admin page'
31
30
 
32
31
  it "creates category" do
33
- subject.should be_redirect
32
+ expect(subject).to be_redirect
34
33
 
35
- Days::Category.last.name.should == params[:category][:name]
34
+ expect(Days::Category.last.name).to eq(params[:category][:name])
36
35
  end
37
36
 
38
37
  context "when category is invalid" do
39
38
  before do
40
- Days::Category.any_instance.stub(:valid? => false, :save => false)
39
+ allow_any_instance_of(Days::Category).to receive(:valid?).and_return(false)
40
+ allow_any_instance_of(Days::Category).to receive(:save).and_return(false)
41
41
  end
42
42
 
43
- specify { subject.status.should == 406 } # not acceptable
43
+ specify { expect(subject.status).to eq(406) } # not acceptable
44
44
 
45
45
  it "renders form" do
46
- render[:data].should == :'admin/categories'
46
+ expect(render[:data]).to eq(:'admin/categories')
47
47
  end
48
48
  end
49
49
  end
@@ -55,27 +55,27 @@ describe Days::App, type: :controller do
55
55
  it_behaves_like 'an admin page'
56
56
 
57
57
  it "updates category" do
58
- subject.should be_redirect
59
- URI.parse(subject['Location']).path.should == '/admin/categories'
58
+ expect(subject).to be_redirect
59
+ expect(URI.parse(subject['Location']).path).to eq('/admin/categories')
60
60
 
61
61
  category.reload
62
- category.name.should == 'Storm'
62
+ expect(category.name).to eq('Storm')
63
63
  end
64
64
 
65
65
  context "when invalid" do
66
66
  before do
67
- Days::Category.any_instance.stub(:valid? => false, :save => false)
67
+ allow_any_instance_of(Days::Category).to receive_messages(:valid? => false, :save => false)
68
68
  end
69
69
 
70
70
  it "renders form" do
71
- render[:data].should == :'admin/categories'
71
+ expect(render[:data]).to eq(:'admin/categories')
72
72
  end
73
73
  end
74
74
 
75
75
  context "with invalid category" do
76
- let(:category) { double.tap { |_| _.stub(id: Days::Category.last.id.succ) } }
76
+ before { category.destroy }
77
77
 
78
- it { should be_not_found }
78
+ it { is_expected.to be_not_found }
79
79
  end
80
80
  end
81
81
 
@@ -86,14 +86,14 @@ describe Days::App, type: :controller do
86
86
 
87
87
  it "destroys category" do
88
88
  expect { subject }.to change { Days::Category.where(id: category.id).count }.from(1).to(0)
89
- subject.should be_redirect
90
- URI.parse(subject.location).path.should == "/admin/categories"
89
+ expect(subject).to be_redirect
90
+ expect(URI.parse(subject.location).path).to eq("/admin/categories")
91
91
  end
92
92
 
93
93
  context "with invalid category" do
94
- let(:category) { double.tap { |_| _.stub(id: Days::Category.last.id.succ) } }
94
+ before { category.destroy }
95
95
 
96
- it { should be_not_found }
96
+ it { is_expected.to be_not_found }
97
97
  end
98
98
  end
99
99
  end