OSDN Git Service

Merge branch 'v04' of git.sourceforge.jp:/gitroot/pettanr/pettanr
authoryasushiito <yas@pen-chan.jp>
Sat, 4 Aug 2012 07:21:44 +0000 (16:21 +0900)
committeryasushiito <yas@pen-chan.jp>
Sat, 4 Aug 2012 07:21:44 +0000 (16:21 +0900)
70 files changed:
.gitignore
app/controllers/comics_controller.rb
app/controllers/original_pictures_controller.rb
app/controllers/panels_controller.rb
app/controllers/stories_controller.rb [new file with mode: 0644]
app/helpers/stories_helper.rb [new file with mode: 0644]
app/models/comic.rb
app/models/original_picture.rb
app/models/panel.rb
app/models/panel_picture.rb
app/models/story.rb [new file with mode: 0644]
app/views/comics/_form.html.erb
app/views/comics/browse.html.erb
app/views/comics/index.html.erb
app/views/comics/list.html.erb
app/views/comics/show.html.erb
app/views/panels/_standard.html.erb
app/views/panels/index.html.erb
app/views/panels/list.html.erb
app/views/stories/_editform.html.erb [new file with mode: 0644]
app/views/stories/_newform.html.erb [new file with mode: 0644]
app/views/stories/browse.html.erb [new file with mode: 0644]
app/views/stories/edit.html.erb [new file with mode: 0644]
app/views/stories/list.html.erb [new file with mode: 0644]
app/views/stories/new.html.erb [new file with mode: 0644]
app/views/stories/show.html.erb [new file with mode: 0644]
app/views/system/browse.html.erb
config/application.rb
config/environments/development.rb
config/environments/production.rb
config/environments/test.rb
config/picture_io.yml.org [new file with mode: 0644]
config/routes.rb
db/migrate/20120618022800_create_stories.rb [new file with mode: 0644]
db/migrate/20120618023403_connect_story.rb [new file with mode: 0644]
db/schema.rb [deleted file]
lib/common.rb [new file with mode: 0644]
lib/test/common_spec.rb [new file with mode: 0644]
spec/cli/create.rb [new file with mode: 0644]
spec/cli/reauth.rb [new file with mode: 0644]
spec/cli/u/comics/create.json [new file with mode: 0644]
spec/cli/u/original_pictures/create.json [new file with mode: 0644]
spec/cli/u/panels/create.json [new file with mode: 0644]
spec/cli/u/stories/create.json [new file with mode: 0644]
spec/cli/update.rb [new file with mode: 0644]
spec/controllers/comics_controller_spec.rb
spec/controllers/original_pictures_controller_spec.rb
spec/controllers/panel_pictures_controller_spec.rb
spec/controllers/panels_controller_spec.rb
spec/controllers/stories_controller_spec.rb [new file with mode: 0644]
spec/factories.rb
spec/models/artist_spec.rb
spec/models/comic_spec.rb
spec/models/original_picture_spec.rb
spec/models/panel_picture_spec.rb
spec/models/panel_spec.rb
spec/models/resource_picture_spec.rb
spec/models/story_spec.rb [new file with mode: 0644]
spec/requests/comics_spec.rb [deleted file]
spec/routing/comics_routing_spec.rb [deleted file]
spec/views/comics/edit.html.erb_spec.rb [deleted file]
spec/views/comics/index.html.erb_spec.rb [deleted file]
spec/views/comics/new.html.erb_spec.rb [deleted file]
spec/views/comics/show.html.erb_spec.rb [deleted file]
vendor/plugins/pettan_importer/db/migrate/20120619100752_create_imports.rb [new file with mode: 0644]
vendor/plugins/pettan_importer/init.rb [new file with mode: 0644]
vendor/plugins/pettan_importer/lib/pettan_importer.rb [new file with mode: 0644]
vendor/plugins/pettan_importer/test/import.json [new file with mode: 0644]
vendor/plugins/pettan_importer/test/import.rb [new file with mode: 0644]
vendor/plugins/pettan_importer/test/import_spec.rb [new file with mode: 0644]

index 84d418e..69e2885 100644 (file)
@@ -1,9 +1,11 @@
 .bundle
 db/*.sqlite3
+db/schema.rb
 log/*.log
 tmp/
 .sass-cache/
 public/image/*
 config/aws.yaml
+config/picture_io.yml
 config/test_layout
 lib/test/temp/
index 1805598..7a033ee 100644 (file)
@@ -1,4 +1,5 @@
 class ComicsController < ApplicationController
+  layout 'test' if Pettanr::TestLayout
   if Const.run_mode == 0
     before_filter :authenticate_user!, :only => [:new, :create, :edit, :update, :destroy]
   else
@@ -57,23 +58,6 @@ class ComicsController < ApplicationController
     end
   end
   
-  def play
-    c = Comic.show(params[:id], @author)
-    cnt = Panel.count(:conditions => ['comic_id = ?', c.id]).to_i
-    @offset = Comic.offset cnt, params[:offset]
-    @panel_count = Comic.panel_count cnt, params[:count]
-    @comic = Comic.play(params[:id])
-    respond_to do |format|
-      format.html # index.html.erb
-      format.json {
-        render :json => @comic.to_json_play
-      }
-      format.jsonp {
-        render :json => "callback(" + @comic.to_json_play + ");"
-      }
-    end
-  end
-  
   def list
     @comics = Comic.all
 
@@ -138,7 +122,6 @@ class ComicsController < ApplicationController
     params[:comic].merge! author_id: @author.id
     @comic = Comic.show(params[:id], @author)
     respond_to do |format|
-      raise ActiveRecord::Forbidden unless @comic.own?(@author)
       if @comic.update_attributes(params[:comic])
         format.html { redirect_to @comic, notice: 'Comic was successfully updated.' }
         format.json { head :ok }
index 31b3ca1..b9e941c 100644 (file)
@@ -129,7 +129,7 @@ class OriginalPicturesController < ApplicationController
   # PUT /original_pictures/1.json
   def update
     @picture_data = set_image params[:original_picture][:file]
-    @original_picture = OriginalPicture.show(params[:id], @author)
+    @original_picture = OriginalPicture.edit(params[:id], @author)
     @original_picture.supply_default @artist
 
     respond_to do |format|
@@ -146,7 +146,7 @@ class OriginalPicturesController < ApplicationController
   # DELETE /original_pictures/1
   # DELETE /original_pictures/1.json
   def destroy
-    @original_picture = OriginalPicture.find(params[:id], @author)
+    @original_picture = OriginalPicture.edit(params[:id], @author)
     OriginalPicture.transaction do
       @original_picture.destroy
     end
index 527fcf0..abae3f7 100644 (file)
@@ -3,12 +3,6 @@ class PanelsController < ApplicationController
   before_filter :authenticate_user!, :only => [:index, :show, :new, :edit, :create, :update, :destroy]
   before_filter :authenticate_admin!, :only => [:list, :browse]
 
-  private
-  
-  def treat_param panel
-    panel.author_id = @author.id
-  end
-  
   public
   
   # GET /panels
@@ -64,7 +58,7 @@ class PanelsController < ApplicationController
 
   def new
     @panel = Panel.new
-    @panel.supply_default @author
+    @panel.supply_default
 
     respond_to do |format|
       format.html # new.html.erb
@@ -84,14 +78,14 @@ class PanelsController < ApplicationController
   # POST /panels
   # POST /panels.json
   def create
+    @panel = Panel.new
+    @panel.supply_default
     if params[:json]
       jsn = JSON.parse(params[:json])
     end
     @prm = params[:panel] || jsn
-    @panel = Panel.new(@prm)
-    treat_param @panel
-#    @comic = Comic.find @panel.comic_id
-
+    @panel.attributes = @prm
+    @panel.overwrite @author
     respond_to do |format|
       if @panel.store
         format.html { redirect_to @panel, notice: 'Panel was successfully created.' }
@@ -106,48 +100,34 @@ class PanelsController < ApplicationController
   # PUT /panels/1
   # PUT /panels/1.json
   def update
-    @panel = Panel.find(params[:id])
-    if @panel.own? @author
-      if params[:json]
-        jsn = JSON.parse(params[:json])
-      end
-      @prm = params[:panel] || jsn
-      respond_to do |format|
-        Panel.transaction do
-          if params[:panel][:t] and params[:panel][:t].to_i != @panel.t
-            @panel.move_to params[:panel][:t].to_i
-          end
-          @panel.attributes = @prm
-          if @panel.store
-            format.html { redirect_to @panel, notice: 'Panel was successfully updated.' }
-            format.json { head :ok }
-          else
-            format.html { render action: "edit" }
-            format.json { render json: @panel.errors, status: :unprocessable_entity }
-          end
-        end
+    @panel = Panel.edit(params[:id], @author)
+    if params[:json]
+      jsn = JSON.parse(params[:json])
+    end
+    @prm = params[:panel] || jsn
+    @panel.attributes = @prm
+    @panel.overwrite @author
+    respond_to do |format|
+      if @panel.store
+        format.html { redirect_to @panel, notice: 'Panel was successfully updated.' }
+        format.json { head :ok }
+      else
+        format.html { render action: "edit" }
+        format.json { render json: @panel.errors, status: :unprocessable_entity }
       end
-    else
-      format.html { render action: "edit" }
-      format.json { render json: @panel.errors, status: :unprocessable_entity }
     end
   end
 
   # DELETE /panels/1
   # DELETE /panels/1.json
   def destroy
-    @panel = Panel.find(params[:id])
-    if @panel.own? @author
-      respond_to do |format|
-        Panel.transaction do
-          @panel.destroy_and_shorten
-          format.html { redirect_to panels_url }
-          format.json { head :ok }
-        end
+    @panel = Panel.edit(params[:id], @author)
+    respond_to do |format|
+      Panel.transaction do
+        @panel.destroy
+        format.html { redirect_to panels_url }
+        format.json { head :ok }
       end
-    else
-      format.html { render action: "edit" }
-      format.json { render json: @panel.errors, status: :unprocessable_entity }
     end
   end
   
diff --git a/app/controllers/stories_controller.rb b/app/controllers/stories_controller.rb
new file mode 100644 (file)
index 0000000..f2ee082
--- /dev/null
@@ -0,0 +1,118 @@
+class StoriesController < ApplicationController
+  layout 'test' if Pettanr::TestLayout
+  if Const.run_mode == 0
+    before_filter :authenticate_user!, :only => [:new, :create, :edit, :update, :destroy]
+  else
+    before_filter :authenticate_user!, :only => [:index, :show, :new, :create, :edit, :update, :destroy]
+  end
+  before_filter :authenticate_admin!, :only => [:list, :browse]
+
+  def show
+    @comic = Comic.show(params[:id], @author)
+    cnt = Story.count(:conditions => ['comic_id = ?', @comic.id]).to_i
+    @offset = Story.offset cnt, params[:offset]
+    @panel_count = Story.panel_count cnt, params[:count]
+    @stories = Story.list(@comic, @author, @offset, @panel_count)
+    respond_to do |format|
+      format.html # index.html.erb
+      format.json {
+        render :json => @stories.to_json_list
+      }
+      format.jsonp {
+        render :json => "callback(" + @stories.to_json_list + ");"
+      }
+    end
+  end
+  
+  def list
+    @stories = Story.all
+
+    respond_to do |format|
+      format.html { render layout: 'system' }# index.html.erb
+      format.json { render json: @stories }
+    end
+  end
+
+  def browse
+    @story = Story.find(params[:id])
+
+    respond_to do |format|
+      format.html { render layout: 'system' } # show.html.erb
+      format.json { render json: @story }
+    end
+  end
+  
+  # GET /stories/new
+  # GET /stories/new.js
+  # GET /stories/new.json
+  def new
+    @story = Story.new 
+    @story.supply_default
+    respond_to do |format|
+      format.html # new.html.erb
+      format.js
+      format.json { render json: @story }
+    end
+  end
+
+  # GET /stories/1/edit
+  # GET /stories/1.js/edit
+  def edit
+    @story = Story.show(params[:id], @author)
+    respond_to do |format|
+      format.html 
+      format.js
+    end
+  end
+
+  # POST /stories
+  # POST /stories.json
+  def create
+    @story = Story.new 
+    @story.supply_default
+    @story.attributes = params[:story]
+    @story.overwrite @author
+    
+    respond_to do |format|
+      if @story.store
+        format.html { redirect_to action: :show, id: @story.comic_id }
+        format.json { render json: @story.to_json() }
+      else
+        format.html { render action: "new" }
+        format.json { render json: @story.errors, status: :unprocessable_entity }
+      end
+    end
+  end
+  
+  # PUT /stories/1
+  # PUT /stories/1.json
+  def update
+    @story = Story.edit(params[:id], @author)
+    ot = @story.t
+    @story.attributes = params[:story]
+    @story.overwrite @author
+    respond_to do |format|
+      if @story.store ot
+        format.html { redirect_to action: :show, id: @story.comic_id }
+        format.json { head :ok }
+      else
+        format.html { render action: "edit" }
+        format.json { render json: @story.errors, status: :unprocessable_entity }
+      end
+    end
+  end
+
+  # DELETE /stories/1
+  # DELETE /stories/1.js
+  # DELETE /stories/1.json
+  def destroy
+    @story = Story.edit(params[:id], @author)
+    Story.transaction do
+      @story.destroy_and_shorten
+    end
+    respond_to do |format|
+      format.html { redirect_to story_path(@story.comic) }
+      format.json { head :ok }
+    end
+  end
+end
diff --git a/app/helpers/stories_helper.rb b/app/helpers/stories_helper.rb
new file mode 100644 (file)
index 0000000..43e5cd8
--- /dev/null
@@ -0,0 +1,2 @@
+module StoriesHelper
+end
index b280dd3..7c937b1 100644 (file)
@@ -1,12 +1,11 @@
 class Comic < ActiveRecord::Base
-  has_many :panels, :dependent => :destroy
+  has_many :stories
   belongs_to :author
   
-  validates :title, :presence => true, :length => {:maximum => 100}\r
+  validates :title, :presence => true, :length => {:maximum => 100}
   validates :width, :presence => true, :numericality => true, :natural_number => true
   validates :height, :presence => true, :numericality => true, :natural_number => true
   validates :visible, :presence => true, :numericality => true, :inclusion => {:in => 0..3}
-  validates :editable, :presence => true, :numericality => true, :inclusion => {:in => 0..3}
   
   before_save do |r|
     r.supply_default
@@ -14,7 +13,6 @@ class Comic < ActiveRecord::Base
   
   def supply_default
     self.visible = 0 if self.visible.blank?
-    self.editable= 0 if self.editable.blank?
   end
   
   def own? author
@@ -26,10 +24,6 @@ class Comic < ActiveRecord::Base
     self.visible > 0 or self.own?(author)
   end
   
-  def disp_editable
-    editable == 1 ? 'O' : 'X'
-  end
-  
   def disp_visible
     visible == 1 ? 'O' : 'X'
   end
@@ -63,21 +57,6 @@ class Comic < ActiveRecord::Base
     page_size
   end
   
-  def self.offset cnt, prm = nil
-    offset = prm.to_i
-    offset = cnt - 1 if offset >= cnt
-    offset = cnt - offset.abs if offset < 0
-    offset = 0 if offset < 0
-    offset
-  end
-  
-  def self.panel_count cnt, prm = self.default_panel_size
-    count = prm.to_i
-    count = self.max_panel_size if count > self.max_panel_size
-    count = self.default_panel_size if count < 1
-    count
-  end
-  
   def self.list opt = {}, page = 1, page_size = self.default_page_size
     opt.merge!(self.list_opt) unless opt[:include]
     opt.merge!({:conditions => ['visible > 0'], :order => 'updated_at desc', :limit => page_size, :offset => (page -1) * page_size})
@@ -85,11 +64,11 @@ class Comic < ActiveRecord::Base
   end
   
   def self.list_opt
-    {:include => :author}
+    {:include => {:stories => {:panel => {}}, :author => {}}}
   end
   
   def self.list_json_opt
-    {:include => :author}
+    {:include => {:stories => {:panel => {}}, :author => {}}}
   end
   
   def self.show cid, au, opt = {}
@@ -99,27 +78,13 @@ class Comic < ActiveRecord::Base
   end
   
   def self.show_include_opt opt = {}
-    res = [:author]
+    res = {:stories => {:panel => {}}, :author => {}}
     res.push(opt[:include]) if opt[:include]
     res
   end
   
   def self.show_json_include_opt
-    {:include => :author}
-  end
-  
-  def self.play cid, opt = {}
-    Comic.find(cid, include: [
-      :author, 
-      :panels => [
-        :panel_pictures => :resource_picture, 
-        :speech_balloons =>{:balloons => {}, :speeches => {}}
-      ]
-    ], order: 'panels.t')
-  end
-  
-  def to_json_play
-    self.to_json( :include => {:author => {}, :panels => {:methods => :panel_element}})
+    {:include => {:stories => {:panel => {}}, :author => {}}}
   end
   
   def self.visible_count
index 722e110..96740f9 100644 (file)
@@ -59,6 +59,12 @@ class OriginalPicture < ActiveRecord::Base
     pic
   end
   
+  def self.edit cid, artist, opt = {}
+    pic = OriginalPicture.find(cid, :include => self.show_include_opt(opt))
+    raise ActiveRecord::Forbidden unless pic.own?(artist)
+    pic
+  end
+  
   def self.show_include_opt opt = {}
     res = [:license, :resource_picture]
     res.push(opt[:include]) if opt[:include]
index 7f0c878..56cd5b5 100644 (file)
@@ -1,49 +1,31 @@
 #コマ
 class Panel < ActiveRecord::Base
-  belongs_to :comic
   belongs_to :author
   belongs_to :resource_picture
 #  belongs_to :background_picture, :class_name => 'ResourcePicture'
+  has_many :stories
   has_many :panel_pictures, :dependent => :destroy
   has_many :speech_balloons, :dependent => :destroy
   accepts_nested_attributes_for :panel_pictures, :allow_destroy => true
   accepts_nested_attributes_for :speech_balloons, :allow_destroy => true
 
-#  validates :comic_id, :presence => true, :numericality => true, :existence => true, :uniqueness => {:scope => :t} 
   validates :width, :presence => true, :numericality => true, :natural_number => true
   validates :height, :presence => true, :numericality => true, :natural_number => true
   validates :border, :presence => true, :numericality => {:greater_than_or_equal_to => 0}
   validates :x, :numericality => {:allow_blank => true}
   validates :y, :numericality => {:allow_blank => true}
   validates :z, :numericality => {:allow_blank => true, :greater_than => 0}
-  validates :t, :presence => true, :numericality => {:greater_than_or_equal_to => 0}
   validates :author_id, :presence => true, :numericality => true, :existence => true
   
-  def supply_default au
-    return false unless au
-    c = self.comic_id ? Comic.show(self.comic_id, au) : nil
-    if c
-      self.width = c.width if self.width.blank?
-      self.height = c.height if self.height.blank?
-      self.t = Panel.new_t(c.id) if self.t.blank? and self.new_record?
-    end
-    self.border = 0 if self.border.blank?
-    self.author_id = au.id
+  def supply_default
+    self.border = 2
   end
   
-  def self.new_t comic_id
-    r = Panel.max_t(comic_id)
-    r.blank? ? 0 : r.to_i + 1
-  end
-  
-  def self.max_t comic_id
-    Panel.maximum(:t, :conditions => ['comic_id = ?', comic_id])
+  def overwrite au
+    return false unless au
+    self.author_id = au.id
   end
   
-  def self.find_t comic_id, t
-    Panel.find(:first, :conditions => ['comic_id = ? and t = ?', comic_id, t])
-  end
-
   def self.collect_element_value elements, name, ex_nil = false
     e = elements.map {|e|
       e.map {|o|
@@ -112,35 +94,13 @@ class Panel < ActiveRecord::Base
   def store
     res = false
     Panel.transaction do
-      raise ActiveRecord::Rollback unless validate_child
-      f = nil
-      f = Panel.find_t(self.comic_id, self.t) if self.t
-      if f
-        Panel.update_all('t = t + 1', ['comic_id = ? and t >= ?', self.comic_id, self.t])
-      else
-        self.t = Panel.new_t self.comic_id
+      unless validate_child
+        self.errors.add :base , 'invalid time'
+        raise ActiveRecord::Rollback
       end
       res = self.save
     end
-  end
-  
-  def move_to new_t
-    return true if self.t == new_t
-    if self.t > new_t
-      Panel.update_all('t = t + 1', ['comic_id = ? and (t >= ? and t < ?)', self.comic_id, new_t, self.t])
-    else
-      nf = Panel.find_t(self.comic_id, new_t)
-      max_t = Panel.max_t.to_i self.comic_id
-      new_t = max_t if new_t > max_t
-      Panel.update_all('t = t - 1', ['comic_id = ? and (t > ? and t <= ?)', self.comic_id, self.t, new_t])
-    end
-    self.t = new_t
-    self.save
-  end
-  
-  def destroy_and_shorten
-    Panel.update_all('t = t - 1', ['comic_id = ? and (t > ?)', self.comic_id, self.t])
-    self.destroy
+    res
   end
   
   def self.default_page_size
@@ -174,13 +134,12 @@ class Panel < ActiveRecord::Base
   
   def self.list opt = {}, page = 1, page_size = self.default_page_size
     opt.merge!(self.list_opt) unless opt[:include]
-    opt.merge!({:order => 'updated_at desc', :limit => page_size, :offset => (page -1) * page_size})
+    opt.merge!({:conditions => 'panels.publish > 0', :order => 'panels.updated_at desc', :limit => page_size, :offset => (page -1) * page_size})
     Panel.find(:all, opt)
   end
   
   def self.list_opt
     {:include => {
-      :comic => :author, 
       :panel_pictures => {
         :resource_picture => {:artist => {}, :license => {}}
       }, 
@@ -191,7 +150,6 @@ class Panel < ActiveRecord::Base
   
   def self.list_json_opt
     {:include => {
-      :comic => {:author => {}}, 
       :panel_pictures => {
         :resource_picture => {:artist => {}, :license => {}}
       }, 
@@ -206,9 +164,14 @@ class Panel < ActiveRecord::Base
     r
   end
   
+  def self.edit rid, au, opt = {}
+    r = Panel.find(rid, :include => self.show_include_opt(opt))
+    raise ActiveRecord::Forbidden unless r.own?(au)
+    r
+  end
+  
   def self.show_include_opt opt = {}
     res = {
-      :comic => :author, 
       :panel_pictures => {
         :resource_picture => {:artist => {}, :license => {}}
       }, 
@@ -221,7 +184,6 @@ class Panel < ActiveRecord::Base
   
   def self.show_json_include_opt
     {:include => {
-      :comic => {:author => {}}, 
       :panel_pictures => {
         :resource_picture => {:artist => {}, :license => {}}
       }, 
@@ -232,8 +194,7 @@ class Panel < ActiveRecord::Base
   
   def visible? au
     return false unless au
-    return false unless self.comic
-    self.comic.visible?(au) or self.author_id == au.id
+    self.own?(au) or self.publish?
   end
   
   def own? author
@@ -241,6 +202,14 @@ class Panel < ActiveRecord::Base
     self.author_id == author.id
   end
   
+  def usable? au
+    visible? au
+  end
+  
+  def publish?
+    self.publish > 0
+  end
+  
   def sort_by_time
     pe = []
     self.panel_pictures.each do |picture|
index f719af1..eab88aa 100644 (file)
@@ -2,8 +2,15 @@ class PanelPicture < ActiveRecord::Base
   belongs_to :panel
   belongs_to :resource_picture
   
+  validates :panel_id, :numericality => {:allow_blank => true}
+  validates :resource_picture_id, :presence => true, :numericality => true, :existence => true
+  validates :link, :length => {:maximum => 200}
+  validates :x, :presence => true, :numericality => true
+  validates :y, :presence => true, :numericality => true
   validates :width, :presence => true, :numericality => true, :not_zero => true
   validates :height, :presence => true, :numericality => true, :not_zero => true
+  validates :z, :presence => true, :numericality => {:greater_than => 0}
+  validates :t, :presence => true, :numericality => {:greater_than_or_equal_to => 0}
   
   def flip
     res = (self.height < 0 ? '' : 'v') + (self.width == 0 ? '' : 'h')
@@ -59,7 +66,7 @@ class PanelPicture < ActiveRecord::Base
   end
   
   def self.list_json_opt
-    {:include => {:panel => {}, :resource_picture => [:artist, :license]}}
+    {:include => {:panel => {}, :resource_picture => {:artist => {}, :license => {}}}}
   end
   
 end
diff --git a/app/models/story.rb b/app/models/story.rb
new file mode 100644 (file)
index 0000000..26575e6
--- /dev/null
@@ -0,0 +1,193 @@
+#ストーリー
+class Story < ActiveRecord::Base
+  belongs_to :author
+  belongs_to :panel
+  belongs_to :comic
+  
+  validates :comic_id, :presence => true, :numericality => true, :existence => true
+  validates :panel_id, :presence => true, :numericality => true, :existence => true
+  validates :author_id, :presence => true, :numericality => true, :existence => true
+  validates :t, :presence => true, :numericality => {:greater_than_or_equal_to => 0}
+  
+  def supply_default
+    self.t = nil
+  end
+  
+  def overwrite au
+    return false unless au
+    self.author_id = au.id
+  end
+  
+  def own? author
+    return false unless author
+    self.author_id == author.id
+  end
+  
+  def self.edit sid, au
+    res = Story.find sid
+    raise ActiveRecord::Forbidden unless res.own?(au)
+    res
+  end
+  
+  def self.new_t comic_id
+    r = Story.max_t(comic_id)
+    r.blank? ? 0 : r.to_i + 1
+  end
+  
+  def self.max_t comic_id
+    Story.maximum(:t, :conditions => ['comic_id = ?', comic_id])
+  end
+  
+  def self.find_t comic_id, t
+    Story.find(:first, :conditions => ['comic_id = ? and t = ?', comic_id, t])
+  end
+  
+  def self.collect_t story
+    r = Story.find(:all, :conditions => ['comic_id = ?', story.comic_id], :order => 't')
+    r.map {|s| s.t}
+  end
+  
+  def self.serial? ary
+    i = 0
+    ary.compact.sort.each do |t|
+      break false unless t == i
+      i += 1
+    end
+    ary.compact.size == i
+  end
+  
+  def self.validate_t story
+    Story.serial?(Story.collect_t(story))
+  end
+  
+  def insert_shift
+    Story.update_all('t = t + 1', ['comic_id = ? and t >= ?', self.comic_id, self.t])
+  end
+  
+  def lesser_shift old_t
+    self.t = 0 if self.t < 0
+    Story.update_all('t = t + 1', ['comic_id = ? and (t >= ? and t < ?)', self.comic_id, self.t, old_t])
+  end
+  
+  def higher_shift old_t
+    nf = Story.find_t(self.comic_id, self.t)
+    max_t = Story.max_t(self.comic_id).to_i
+    self.t = max_t if self.t > max_t
+    Story.update_all('t = t - 1', ['comic_id = ? and (t > ? and t <= ?)', self.comic_id, old_t, self.t])
+  end
+  
+  def update_shift old_t
+    if self.t > old_t
+      higher_shift old_t
+    else
+      lesser_shift old_t
+    end
+  end
+  
+  def rotate old_t = nil
+    if self.new_record?
+      if self.t.blank?
+        self.t = Story.new_t self.comic_id
+      else
+        self.insert_shift
+      end
+    else
+      if self.t.blank?
+      else
+        self.update_shift old_t
+      end
+    end
+  end
+  
+  def allow?
+    c = self.comic
+    pl = self.panel
+    c and c.own?(self.author) and pl and pl.usable?(self.author)
+  end
+  
+  def store old_t = nil
+    res = false
+    raise ActiveRecord::Forbidden unless self.allow?
+    Story.transaction do
+      self.rotate old_t
+      res = self.save
+      raise ActiveRecord::Rollback unless res
+      res = Story.validate_t(self) 
+      unless res
+        self.errors.add :t, 'unserialized'
+        raise ActiveRecord::Rollback 
+      end
+    end
+    res
+  end
+  
+  def destroy_and_shorten
+    Story.transaction do
+      Story.update_all('t = t - 1', ['comic_id = ? and (t > ?)', self.comic_id, self.t])
+      raise ActiveRecord::Rollback unless self.destroy
+    end
+  end
+  
+  def self.default_panel_size
+    30
+  end
+  
+  def self.max_panel_size
+    200
+  end
+  
+  def self.offset cnt, prm = nil
+    offset = prm.to_i
+    offset = cnt - 1 if offset >= cnt
+    offset = cnt - offset.abs if offset < 0
+    offset = 0 if offset < 0
+    offset
+  end
+  
+  def self.panel_count cnt, prm = self.default_panel_size
+    count = prm.to_i
+    count = self.max_panel_size if count > self.max_panel_size
+    count = self.default_panel_size if count < 1
+    count
+  end
+  
+  def self.list comic, author, offset = 0, limit = Story.default_panel_size
+    opt = self.list_opt
+    opt.merge!({:conditions => ['stories.comic_id = ? and panels.publish > 0', comic.id], :order => 'stories.t', :offset => offset, :limit => limit})
+    Story.find(:all, opt)
+  end
+  
+  def self.list_opt
+    {:include => {
+      :author => {}, 
+      :comic => {
+        :author => {}
+      }, 
+      :panel => {
+        :author => {}, 
+        :panel_pictures => {:resource_picture => {:artist => {}}}, 
+        :speech_balloons =>{:balloons => {}, :speeches => {}}
+      }
+    }}
+  end
+  
+  def self.list_json_opt
+    {:include => {
+      :author => {}, 
+      :comic => {
+        :author => {}
+      }, 
+      :panel => {
+        :author => {}, 
+        :panel_pictures => {:resource_picture => {:artist => {}}}, 
+        :speech_balloons =>{:balloons => {}, :speeches => {}}
+      }
+    }}
+  end
+  
+  def to_json_list
+    self.to_json( :include => {:author => {}, :panels => {:methods => :panel_element}})
+  end
+  
+  
+end
index 62a9a0a..c8e1fb6 100644 (file)
     <%= f.label :visible %><br />
     <%= f.collection_select :visible, [['only me', 0], ['everyone', 3]], :last, :first, :html => {:selected => @comic.visible} %>
   </div>
-  <div class="field">
-    <%= f.label :editable %><br />
-    <%= f.collection_select :editable, [['only me', 0], ['everyone', 3]], :last, :first, :html => {:selected => @comic.editable} %>
-  </div>
 
   <div class="actions">
     <%= f.submit %>
index f963352..c9861b9 100644 (file)
 </p>
 
 <p>
-  <b>editable:</b>
-  <%= @comic.editable %>
-</p>
-
-<p>
   <b>author_id:</b>
   <%= @comic.author_id %>
 </p>
index 9302b79..5ea6d81 100644 (file)
@@ -3,8 +3,7 @@
 <% @comics.each do |comic| %>
   <div>
     <div>
-      <%= link_to h(comic.title), :action => :play, :id => comic.id %>
-      一般投稿:<%= comic.disp_editable %>
+      <%= link_to h(comic.title), :controller => 'stories', :action => :show, :id => comic.id %>
     </div>
     <div>
       作家:<%= h comic.author.name %>
index 8045381..189ada4 100644 (file)
@@ -7,7 +7,6 @@
     <th>width</th>
     <th>height</th>
     <th>visible</th>
-    <th>editable</th>
     <th>author_id</th>
     <th>created_at</th>
     <th>updated_at</th>
@@ -21,7 +20,6 @@
     <td><%= comic.width %></td>
     <td><%= comic.height %></td>
     <td><%= comic.visible %></td>
-    <td><%= comic.editable %></td>
     <td><%= link_to comic.author_id, :controller => '/authors', :action => :browse, :id => comic.author_id %></td>
     <td><%= comic.created_at %></td>
     <td><%= comic.updated_at %></td>
index fb358d2..f77abc2 100644 (file)
 </p>
 
 <p>
-  <b>editable:</b>
-  <%= @comic.editable %>
-</p>
-
-<p>
   <b>author_id:</b>
   <%= @comic.author_id %>
 </p>
index e1ae5ad..fff9389 100644 (file)
@@ -1,6 +1,3 @@
-<span>
-t:<%= @panel.t %>
-</span>
 <div class="panel" style="width:<%= @panel.width %>px;height:<%= @panel.height %>px;overflow:hidden; border:solid black <%= @panel.border %>px; background:white;">
   <% @panel.each_element do |elm| %>
     <% if elm.kind_of?(PanelPicture) %>
@@ -21,20 +18,9 @@ t:<%= @panel.t %>
   <% end %>
 </div>
 <span>
-Comic:<%= @panel.comic_id %>
-</span>
-<span>
-resource_picture:<%= @panel.resource_picture_id %>
-</span>
-<span>
 Width:<%= @panel.width %>
 </span>
 <span>
 Height:<%= @panel.height %>
 </span>
-<%= form_for(@panel) do |f| %>
-    <%= f.submit 'move to' %>
-     <%= f.number_field :t %>
-<% end %>
-<%= button_to 'Destroy', @panel, confirm: 'Are you sure?', method: :delete %>
 
index 8b37c7a..f209aca 100644 (file)
@@ -1,7 +1,6 @@
 <h1>Listing panels 最近の投稿</h1>
 <% @panels.each do |panel| %>
   <div>
-    <%= link_to h(panel.comic.title), panel.comic %>t:<%= panel.t %>
 <div class="panel" style="width:<%= panel.width %>px;height:<%= panel.height %>px;overflow:hidden; border:solid black <%= panel.border %>px; background:white;">
   <% panel.panel_pictures.each do |panel_picture| %>
     <div id="vPicture<%= panel_picture.id -%>" class="panel_picture" style="position:relative;  top:<%= panel_picture.y -%>px; left:<%= panel_picture.x -%>px; z-index:<%= panel_picture.z -%>; ">
@@ -18,7 +17,7 @@
     <%= h panel.author.name %> <%= panel.updated_at %>
   </div>
 <% end %>
-<%= link_to 'open form', new_panel_path, :remote => true %>\r
-  <div id="newpanel">\r
-    uploader\r
-  </div>\r
+<%= link_to 'open form', new_panel_path, :remote => true %>
+  <div id="newpanel">
+    uploader
+  </div>
index aaa0945..ded452e 100644 (file)
@@ -1,20 +1,19 @@
 <h1>Listing panels</h1>
-<%= link_to 'open form', new_panel_path, :remote => true %>\r
-  <div id="newpanel">\r
-    uploader\r
-  </div>\r
+<%= link_to 'open form', new_panel_path, :remote => true %>
+  <div id="newpanel">
+    uploader
+  </div>
 
 <table>
   <tr>
     <th>id</th>
-    <th>Comic</th>
     <th>Width</th>
     <th>Height</th>
     <th>Border</th>
     <th>x</th>
     <th>y</th>
     <th>z</th>
-    <th>t</th>
+    <th>publish</th>
     <th>author_id</th>
     <th>created_at</th>
     <th>updated_at</th>
 <% @panels.each do |panel| %>
   <tr>
     <td><%= link_to panel.id, :action => :browse, :id => panel.id %></td>
-    <td><%= link_to panel.comic_id, :controller => 'comics', :action => :browse, :id => panel.comic_id %></td>
     <td><%= panel.width %></td>
     <td><%= panel.height %></td>
     <td><%= panel.border %></td>
     <td><%= panel.x %></td>
     <td><%= panel.y %></td>
     <td><%= panel.z %></td>
-    <td><%= panel.t %></td>
+    <td><%= panel.publish %></td>
     <td><%= link_to panel.author_id, :controller => '/authors', :action => :browse, :id => panel.author_id %></td>
     <td><%= panel.created_at %></td>
     <td><%= panel.updated_at %></td>
diff --git a/app/views/stories/_editform.html.erb b/app/views/stories/_editform.html.erb
new file mode 100644 (file)
index 0000000..9cc6dd4
--- /dev/null
@@ -0,0 +1,28 @@
+<%= form_for(@story) do |f| %>
+  <% if @story.errors.any? %>
+    <div id="error_explanation">
+      <h2><%= pluralize(@story.errors.count, "error") %> prohibited this comic from being saved:</h2>
+
+      <ul>
+      <% @story.errors.full_messages.each do |msg| %>
+        <li><%= msg %></li>
+      <% end %>
+      </ul>
+    </div>
+  <% end %>
+
+  <div class="field">
+    <%= f.hidden_field :comic_id %>
+  </div>
+  <div class="field">
+    <%= f.number_field :t %>
+  </div>
+  <div class="field">
+    <%= f.hidden_field :panel_id %>
+  </div>
+
+  <div class="actions">
+    <%= f.submit %>
+  </div>
+<% end %>
+<%= button_to 'Destroy', @story.panel, confirm: 'Are you sure?', method: :delete %>
diff --git a/app/views/stories/_newform.html.erb b/app/views/stories/_newform.html.erb
new file mode 100644 (file)
index 0000000..f7b5749
--- /dev/null
@@ -0,0 +1,27 @@
+<%= form_for(@story) do |f| %>
+  <% if @story.errors.any? %>
+    <div id="error_explanation">
+      <h2><%= pluralize(@story.errors.count, "error") %> prohibited this comic from being saved:</h2>
+
+      <ul>
+      <% @story.errors.full_messages.each do |msg| %>
+        <li><%= msg %></li>
+      <% end %>
+      </ul>
+    </div>
+  <% end %>
+
+  <div class="field">
+    <%= f.number_field :comic_id %>
+  </div>
+  <div class="field">
+    <%= f.number_field :t %>
+  </div>
+  <div class="field">
+    <%= f.number_field :panel_id %>
+  </div>
+
+  <div class="actions">
+    <%= f.submit %>
+  </div>
+<% end %>
diff --git a/app/views/stories/browse.html.erb b/app/views/stories/browse.html.erb
new file mode 100644 (file)
index 0000000..24a7a6c
--- /dev/null
@@ -0,0 +1,28 @@
+<p id="notice"><%= notice %></p>
+
+<p>
+  <b>comic_id:</b>
+  <%= @story.comic_id %>
+</p>
+
+<p>
+  <b>panel_id:</b>
+  <%= @story.panel_id %>
+</p>
+
+<p>
+  <b>t:</b>
+  <%= @story.t %>
+</p>
+
+<p>
+  <b>author_id:</b>
+  <%= @story.author_id %>
+</p>
+
+<p>
+  <b>updated_at:</b>
+  <%= @story.updated_at %>
+</p>
+
+<%= link_to 'Back', :action => :list %>
diff --git a/app/views/stories/edit.html.erb b/app/views/stories/edit.html.erb
new file mode 100644 (file)
index 0000000..9f2b842
--- /dev/null
@@ -0,0 +1 @@
+<%= render 'editform' %>
diff --git a/app/views/stories/list.html.erb b/app/views/stories/list.html.erb
new file mode 100644 (file)
index 0000000..6fae81c
--- /dev/null
@@ -0,0 +1,29 @@
+<h1>Listing Story</h1>
+
+<table>
+  <tr>
+    <th>id</th>
+    <th>comic_id</th>
+    <th>panel_id</th>
+    <th>t</th>
+    <th>author_id</th>
+    <th>created_at</th>
+    <th>updated_at</th>
+    <th></th>
+  </tr>
+
+<%  @stories.each do |story| %>
+  <tr>
+    <td><%= link_to story.id, :action => :browse, :id => story.id %></td>
+    <td><%= story.comic_id %></td>
+    <td><%= story.panel_id %></td>
+    <td><%= story.t %></td>
+    <td><%= link_to story.author_id, :controller => '/authors', :action => :browse, :id => story.author_id %></td>
+    <td><%= story.created_at %></td>
+    <td><%= story.updated_at %></td>
+    <td>
+    </td>
+  </tr>
+<% end %>
+</table>
+
diff --git a/app/views/stories/new.html.erb b/app/views/stories/new.html.erb
new file mode 100644 (file)
index 0000000..47cd6d9
--- /dev/null
@@ -0,0 +1 @@
+<%= render 'newform' %>
diff --git a/app/views/stories/show.html.erb b/app/views/stories/show.html.erb
new file mode 100644 (file)
index 0000000..dfa9eff
--- /dev/null
@@ -0,0 +1,25 @@
+<h1><%= h @comic.title %></h1>
+
+<% @stories.each do |story| %>
+  <% @story = story %>
+  <% @panel = story.panel %>
+  <%= render 'panels/standard' %>
+  <% if story.author.id == @author.id -%>
+    <span>
+    t:<%= story.t %>
+    </span>
+<%= button_to 'Destroy', @story, confirm: 'Are you sure?', method: :delete %>
+    <%= render 'editform' %>
+    <%= link_to 'open js', edit_story_path(story), :remote => true %>
+      <div id="story-update-<%= @story.id -%>">
+        t
+      </div>
+  <% end -%>
+<% end %>
+<% if @comic.author.id == @author.id -%>
+  <%= link_to 'add panel', new_story_path, :remote => true %>
+    <div id="story-create">
+      t
+    </div>
+<% end %>
+<%= link_to 'Back', comics_path %>
index 836bacd..f05ec07 100644 (file)
   </tr>
   <tr>
     <td>
+      <%= link_to 'stories', :controller => 'stories', :action => :list %>
+    </td>
+  </tr>
+  <tr>
+    <td>
       <%= link_to 'original_pictures', :controller => 'original_pictures', :action => :list %>
     </td>
   </tr>
index 2b7bcb8..00a00f7 100644 (file)
@@ -17,6 +17,7 @@ if defined?(Bundler)
 end
 
 module Pettanr
+  VERSION = '0.4'
   class Application < Rails::Application
     # Settings in config/environments/* take precedence over those specified here.
     # Application configuration should go into files in config/initializers
@@ -56,6 +57,14 @@ config.assets.initialize_on_precompile = false
     config.autoload_paths += %W(#{config.root}/lib/validators)
   end
 end
+y = YAML.load(open(Rails.root + 'config/picture_io.yml').read)
+require y[Rails.env]["adapter"]
+pio = PictureIO.const_get y[Rails.env]["io"]
+PictureIO.setup do |config|
+  config.original_picture_io = pio.new y[Rails.env]["original_picture"]
+  config.resource_picture_io = pio.new y[Rails.env]["resource_picture"]
+  config.system_picture_io = pio.new y[Rails.env]["system_picture"]
+end
 module ActiveRecord
   class Forbidden < ActiveRecordError
   end
index 6820832..90b4815 100644 (file)
@@ -29,12 +29,6 @@ Pettanr::Application.configure do
   config.assets.debug = true
 end
 
-require 'local_picture'
-PictureIO.setup do |config|
-  config.original_picture_io = PictureIO::LocalPicture.new '/sites/original/pettanr/'
-  config.resource_picture_io = PictureIO::LocalPicture.new  '/sites/resource/pettanr/'
-  config.system_picture_io = PictureIO::LocalPicture.new  '/sites/system/pettanr/'
-end
 module Pettanr
   if File.exist? Rails.root + 'config/test_layout'
     TestLayout = 'test'
index bce780b..b80671e 100644 (file)
@@ -66,9 +66,3 @@ AWS::S3::Base.establish_connection!(
   :access_key_id => y["access_key_id"], 
   :secret_access_key => y["secret_access_key"]
 )
-require 's3_picture'
-PictureIO.setup do |config|
-  config.original_picture_io = PictureIO::S3Picture.new 'pettanr-original'
-  config.resource_picture_io = PictureIO::S3Picture.new 'pettanr-stable'
-  config.system_picture_io = PictureIO::S3Picture.new  'pettanr-system'
-end
index d50c384..e05e0f3 100644 (file)
@@ -38,12 +38,6 @@ Pettanr::Application.configure do
   config.active_support.deprecation = :stderr
 end
 
-require 'local_picture'
-PictureIO.setup do |config|
-  config.original_picture_io = PictureIO::LocalPicture.new '/sites/original/pettanr/'
-  config.resource_picture_io = PictureIO::LocalPicture.new  '/sites/resource/pettanr/'
-  config.system_picture_io = PictureIO::LocalPicture.new  '/sites/system/pettanr/'
-end
 module Pettanr
   if File.exist? Rails.root + 'config/test_layout'
     TestLayout = 'test'
diff --git a/config/picture_io.yml.org b/config/picture_io.yml.org
new file mode 100644 (file)
index 0000000..d1399fe
--- /dev/null
@@ -0,0 +1,20 @@
+development:
+  adapter: local_picture
+  io: LocalPicture
+  original_picture: /pettanr/dev/o/
+  resource_picture: /pettanr/dev/r/
+  system_picture: /pettanr/dev/s/
+
+test:
+  adapter: local_picture
+  io: LocalPicture
+  original_picture: /pettanr/test/o/
+  resource_picture: /pettanr/test/r/
+  system_picture: /pettanr/test/s/
+
+production:
+  adapter: s3_picture
+  io: S3Picture
+  original_picture: pettanr-original
+  resource_picture: pettanr-picture
+  system_picture: pettanr-system
index 0eb6117..7761f23 100644 (file)
@@ -90,10 +90,12 @@ Pettanr::Application.routes.draw do
     end
   end
   resources :original_pictures do
+    new do
+      get :new
+    end
     collection do
       get :index
       get :show
-      get :new
       post :create
       get :list
       get :browse
@@ -118,7 +120,25 @@ Pettanr::Application.routes.draw do
       delete :destroy
     end
   end
+  resources :stories do
+    new do
+      get :new
+    end
+    collection do
+      post :create
+      get :list
+      get :browse
+    end
+    member do
+      get :show
+      put :update
+      delete :destroy
+    end
+  end
   resources :comics do #, except: [:new, :edit]
+    new do
+      get :new
+    end
     collection do
       get :index
       get :show
diff --git a/db/migrate/20120618022800_create_stories.rb b/db/migrate/20120618022800_create_stories.rb
new file mode 100644 (file)
index 0000000..0e144cd
--- /dev/null
@@ -0,0 +1,12 @@
+class CreateStories < ActiveRecord::Migration
+  def change
+    create_table :stories do |t|
+      t.integer :comic_id, :null => false, :default => 0
+      t.integer :panel_id, :null => false, :default => 0
+      t.integer :author_id, :null => false, :default => 0
+      t.integer :t, :null => false, :default => 0
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20120618023403_connect_story.rb b/db/migrate/20120618023403_connect_story.rb
new file mode 100644 (file)
index 0000000..1806125
--- /dev/null
@@ -0,0 +1,35 @@
+class ConnectStory < ActiveRecord::Migration
+  def up
+    pn = Panel.find :all
+    pn.each do |i|
+      c = i.comic_id
+      t = i.t
+      a = i.author_id
+      s = i.id
+      st = Story.find(:first, :conditions => ['comic_id = ? and panel_id = ? and t = ?', c, s, t])
+      st = Story.new(:comic_id => c, :panel_id => s, :t => t) unless st
+      st.author_id = a
+      st.save!
+    end
+    remove_column :comics, :editable
+    remove_column :panels, :comic_id
+    remove_column :panels, :t
+    add_column :panels, :publish, :integer, :null => false, :default => 0
+  end
+
+  def down
+    add_column :comics, :editable, :integer, :null => false, :default => 0
+    add_column :panels, :comic_id, :integer, :null => false, :default => 0
+    add_column :panels, :t, :integer, :null => false, :default => 0
+    remove_column :panels, :publish
+    st = Story.find :all
+    st.each do |i|
+      c = i.comic_id
+      t = i.t
+      pn = Panel.find(i.panel_id)
+      pn.t = t
+      pn.comic_id = c
+      pn.save!
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
deleted file mode 100644 (file)
index 771d543..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-# encoding: UTF-8\r
-# This file is auto-generated from the current state of the database. Instead\r
-# of editing this file, please use the migrations feature of Active Record to\r
-# incrementally modify your database, and then regenerate this schema definition.\r
-#\r
-# Note that this schema.rb definition is the authoritative source for your\r
-# database schema. If you need to create the application database on another\r
-# system, you should be using db:schema:load, not running all the migrations\r
-# from scratch. The latter is a flawed and unsustainable approach (the more migrations\r
-# you'll amass, the slower it'll run and the greater likelihood for issues).\r
-#\r
-# It's strongly recommended to check this file into your version control system.\r
-\r
-ActiveRecord::Schema.define(:version => 20120424100555) do\r
-\r
-  create_table "admins", :force => true do |t|\r
-    t.string   "email",                                 :default => "", :null => false\r
-    t.string   "encrypted_password",     :limit => 128, :default => "", :null => false\r
-    t.string   "reset_password_token"\r
-    t.datetime "reset_password_sent_at"\r
-    t.datetime "remember_created_at"\r
-    t.integer  "sign_in_count",                         :default => 0\r
-    t.datetime "current_sign_in_at"\r
-    t.datetime "last_sign_in_at"\r
-    t.string   "current_sign_in_ip"\r
-    t.string   "last_sign_in_ip"\r
-    t.string   "confirmation_token"\r
-    t.datetime "confirmed_at"\r
-    t.datetime "confirmation_sent_at"\r
-    t.string   "authentication_token"\r
-    t.integer  "approve",                               :default => 0,  :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "admins", ["authentication_token"], :name => "index_admins_on_authentication_token", :unique => true\r
-  add_index "admins", ["confirmation_token"], :name => "index_admins_on_confirmation_token", :unique => true\r
-  add_index "admins", ["email"], :name => "index_admins_on_email", :unique => true\r
-  add_index "admins", ["reset_password_token"], :name => "index_admins_on_reset_password_token", :unique => true\r
-\r
-  create_table "artists", :force => true do |t|\r
-    t.string   "email"\r
-    t.string   "name"\r
-    t.string   "homepage_url"\r
-    t.string   "api_url"\r
-    t.integer  "default_license_id", :default => 0, :null => false\r
-    t.datetime "crowled_at"\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-    t.integer  "author_id"\r
-  end\r
-\r
-  create_table "authors", :force => true do |t|\r
-    t.string   "name"\r
-    t.integer  "user_id",    :default => 0, :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "authors", ["user_id"], :name => "index_authors_on_user_id", :unique => true\r
-\r
-  create_table "balloons", :force => true do |t|\r
-    t.integer  "speech_balloon_id", :null => false\r
-    t.integer  "system_picture_id", :null => false\r
-    t.integer  "x",                 :null => false\r
-    t.integer  "y",                 :null => false\r
-    t.integer  "width",             :null => false\r
-    t.integer  "height",            :null => false\r
-    t.string   "caption"\r
-    t.string   "settings"\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "balloons", ["speech_balloon_id"], :name => "index_balloons_on_speech_balloon_id"\r
-\r
-  create_table "comics", :force => true do |t|\r
-    t.string   "title",      :limit => 100,                :null => false\r
-    t.integer  "width",                                    :null => false\r
-    t.integer  "height",                                   :null => false\r
-    t.integer  "visible",                   :default => 0, :null => false\r
-    t.integer  "editable",                  :default => 0, :null => false\r
-    t.integer  "author_id",                                :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "comics", ["author_id"], :name => "index_comics_on_author_id"\r
-\r
-  create_table "common_licenses", :force => true do |t|\r
-    t.integer  "license_id",                       :null => false\r
-    t.string   "name",                             :null => false\r
-    t.string   "url",                              :null => false\r
-    t.integer  "cc_by",             :default => 0, :null => false\r
-    t.integer  "cc_sa",             :default => 0, :null => false\r
-    t.integer  "cc_nd",             :default => 0, :null => false\r
-    t.integer  "cc_nc",             :default => 0, :null => false\r
-    t.integer  "no_resize",         :default => 0, :null => false\r
-    t.integer  "no_flip",           :default => 0, :null => false\r
-    t.integer  "no_convert",        :default => 0, :null => false\r
-    t.integer  "keep_aspect_ratio", :default => 0, :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  create_table "licenses", :force => true do |t|\r
-    t.string   "name",                             :null => false\r
-    t.string   "url",                              :null => false\r
-    t.integer  "cc_by",             :default => 0, :null => false\r
-    t.integer  "cc_sa",             :default => 0, :null => false\r
-    t.integer  "cc_nd",             :default => 0, :null => false\r
-    t.integer  "cc_nc",             :default => 0, :null => false\r
-    t.integer  "no_resize",         :default => 0, :null => false\r
-    t.integer  "no_flip",           :default => 0, :null => false\r
-    t.integer  "no_convert",        :default => 0, :null => false\r
-    t.integer  "keep_aspect_ratio", :default => 0, :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "licenses", ["url"], :name => "index_licenses_on_url", :unique => true\r
-\r
-  create_table "original_licenses", :force => true do |t|\r
-    t.integer  "license_id",                       :null => false\r
-    t.string   "name",                             :null => false\r
-    t.string   "url",                              :null => false\r
-    t.integer  "cc_by",             :default => 0, :null => false\r
-    t.integer  "cc_sa",             :default => 0, :null => false\r
-    t.integer  "cc_nd",             :default => 0, :null => false\r
-    t.integer  "cc_nc",             :default => 0, :null => false\r
-    t.integer  "no_resize",         :default => 0, :null => false\r
-    t.integer  "no_flip",           :default => 0, :null => false\r
-    t.integer  "no_convert",        :default => 0, :null => false\r
-    t.integer  "keep_aspect_ratio", :default => 0, :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  create_table "original_pictures", :force => true do |t|\r
-    t.string   "ext",                       :null => false\r
-    t.integer  "width",                     :null => false\r
-    t.integer  "height",                    :null => false\r
-    t.integer  "filesize",                  :null => false\r
-    t.integer  "artist_id",  :default => 0, :null => false\r
-    t.integer  "license_id", :default => 0, :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "original_pictures", ["artist_id"], :name => "index_original_pictures_on_artist_id"\r
-\r
-  create_table "panel_pictures", :force => true do |t|\r
-    t.integer  "panel_id",                           :null => false\r
-    t.integer  "resource_picture_id",                :null => false\r
-    t.string   "link",                :limit => 200\r
-    t.integer  "x",                                  :null => false\r
-    t.integer  "y",                                  :null => false\r
-    t.integer  "z",                                  :null => false\r
-    t.integer  "t",                                  :null => false\r
-    t.integer  "width",                              :null => false\r
-    t.integer  "height",                             :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "panel_pictures", ["panel_id", "t"], :name => "panel_pictures_idt", :unique => true\r
-\r
-  create_table "panels", :force => true do |t|\r
-    t.integer  "comic_id"\r
-    t.integer  "width",      :default => 200, :null => false\r
-    t.integer  "height",     :default => 80,  :null => false\r
-    t.integer  "border",     :default => 1,   :null => false\r
-    t.integer  "x"\r
-    t.integer  "y"\r
-    t.integer  "z"\r
-    t.integer  "t",                           :null => false\r
-    t.integer  "author_id",                   :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "panels", ["author_id"], :name => "index_panels_on_author_id"\r
-\r
-  create_table "resource_pictures", :force => true do |t|\r
-    t.string   "ext",                                :null => false\r
-    t.integer  "width",                              :null => false\r
-    t.integer  "height",                             :null => false\r
-    t.integer  "filesize",                           :null => false\r
-    t.integer  "artist_id",           :default => 0, :null => false\r
-    t.integer  "license_id",          :default => 0, :null => false\r
-    t.integer  "original_picture_id",                :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  create_table "speech_balloon_templates", :force => true do |t|\r
-    t.string   "name",       :limit => 50,                :null => false\r
-    t.string   "classname",  :limit => 50,                :null => false\r
-    t.string   "caption",    :limit => 30,                :null => false\r
-    t.integer  "t",                        :default => 0, :null => false\r
-    t.string   "settings",                                :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "speech_balloon_templates", ["name"], :name => "speech_balloon_templates_name", :unique => true\r
-  add_index "speech_balloon_templates", ["t"], :name => "speech_balloon_templates_t", :unique => true\r
-\r
-  create_table "speech_balloons", :force => true do |t|\r
-    t.integer  "panel_id",                                 :null => false\r
-    t.integer  "speech_balloon_template_id",               :null => false\r
-    t.string   "classname",                  :limit => 50, :null => false\r
-    t.integer  "z",                                        :null => false\r
-    t.integer  "t",                                        :null => false\r
-    t.string   "settings"\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "speech_balloons", ["panel_id"], :name => "index_speech_balloons_on_panel_id"\r
-\r
-  create_table "speeches", :force => true do |t|\r
-    t.integer  "speech_balloon_id", :null => false\r
-    t.string   "content"\r
-    t.integer  "x",                 :null => false\r
-    t.integer  "y",                 :null => false\r
-    t.integer  "width",             :null => false\r
-    t.integer  "height",            :null => false\r
-    t.string   "settings"\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "speeches", ["speech_balloon_id"], :name => "index_speeches_on_speech_balloon_id"\r
-\r
-  create_table "system_pictures", :force => true do |t|\r
-    t.string   "ext",                      :null => false\r
-    t.integer  "width",                    :null => false\r
-    t.integer  "height",                   :null => false\r
-    t.integer  "filesize",                 :null => false\r
-    t.string   "md5",        :limit => 32, :null => false\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  create_table "users", :force => true do |t|\r
-    t.string   "email",                                 :default => "", :null => false\r
-    t.string   "encrypted_password",     :limit => 128, :default => "", :null => false\r
-    t.string   "reset_password_token"\r
-    t.datetime "reset_password_sent_at"\r
-    t.datetime "remember_created_at"\r
-    t.integer  "sign_in_count",                         :default => 0\r
-    t.datetime "current_sign_in_at"\r
-    t.datetime "last_sign_in_at"\r
-    t.string   "current_sign_in_ip"\r
-    t.string   "last_sign_in_ip"\r
-    t.string   "authentication_token"\r
-    t.string   "confirmation_token"\r
-    t.datetime "confirmed_at"\r
-    t.datetime "confirmation_sent_at"\r
-    t.datetime "created_at"\r
-    t.datetime "updated_at"\r
-  end\r
-\r
-  add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token", :unique => true\r
-  add_index "users", ["confirmation_token"], :name => "index_users_on_confirmation_token", :unique => true\r
-  add_index "users", ["email"], :name => "index_users_on_email", :unique => true\r
-  add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true\r
-\r
-end\r
diff --git a/lib/common.rb b/lib/common.rb
new file mode 100644 (file)
index 0000000..44ebcdf
--- /dev/null
@@ -0,0 +1,14 @@
+require 'json'
+
+module JSON
+  def self.parse_no_except(data)
+    res = data
+    begin
+      res = JSON.parse(data) if data.is_a?(String)
+    rescue 
+      return false
+    end
+    res
+  end
+end
+  
diff --git a/lib/test/common_spec.rb b/lib/test/common_spec.rb
new file mode 100644 (file)
index 0000000..5a699f2
--- /dev/null
@@ -0,0 +1,29 @@
+# -*- encoding: utf-8 -*-
+#共通処理
+require 'common'
+
+describe JSON do
+  before do
+  end
+
+  describe '例外なしパースに於いて' do
+    context 'テキストを渡されたとき' do
+      it 'Json解析している' do
+        JSON.should_receive(:parse).with(any_args).exactly(1)
+        r = JSON.parse_no_except '{}'
+      end
+      it '単数データならHashで返す' do
+        r = JSON.parse_no_except '{}'
+        r.is_a?(Hash).should be_true
+      end
+    end
+    context 'パース失敗したとき' do
+      it 'Falseを返す' do
+        JSON.should_receive(:parse).with(any_args).and_raise('StandardError')
+        r = JSON.parse_no_except ''
+        r.should be_false
+      end
+    end
+  end
+end
+
diff --git a/spec/cli/create.rb b/spec/cli/create.rb
new file mode 100644 (file)
index 0000000..7a1588c
--- /dev/null
@@ -0,0 +1,14 @@
+if ARGV.size < 2\r
+  puts 'create.rb subdir controller {filename=create.json}'\r
+  exit\r
+end\r
+domain = 'http://localhost:3000'\r
+user = ARGV[0].to_s\r
+ctl = ARGV[1]\r
+f = ARGV[2] ? ARGV[2].to_s+'_create' : 'create'\r
+path = File.expand_path(File.dirname(__FILE__))\r
+filename = path + "/#{user}/#{ctl}/#{f}.json"\r
+\r
+cmd = "curl -d @#{filename} #{domain}/#{ctl}.json  -X POST -H \"Content-Type: application/json\""\r
+puts cmd\r
+exec cmd\r
diff --git a/spec/cli/reauth.rb b/spec/cli/reauth.rb
new file mode 100644 (file)
index 0000000..84060c2
--- /dev/null
@@ -0,0 +1,31 @@
+if ARGV.size < 2\r
+  puts 'reauth.rb subdir new_auth_token'\r
+  exit\r
+end\r
+require 'json'\r
+path = File.expand_path(File.dirname(__FILE__)) + '/' + (ARGV[0].to_s + '/' +  '*')\r
+puts 'path:'\r
+puts path\r
+Dir.glob path  do |filename|\r
+  if File.directory?(filename)\r
+    puts 'search dir:'\r
+    puts filename\r
+    Dir.glob filename + '/*' do |filename2|\r
+      d = nil\r
+      puts 'replace:'\r
+      puts filename2\r
+      File.open(filename2, 'rb') do |f|\r
+        d = f.read\r
+      end\r
+      j = JSON.parse d\r
+      ot = j["auth_token"]\r
+      b = d.gsub /#{ot}/, ARGV[1].to_s\r
+      File.open(filename2, 'wb') do |f|\r
+        f.write b\r
+      end\r
+    end\r
+  else\r
+    puts 'ignore file:'\r
+    puts filename\r
+  end\r
+end\r
diff --git a/spec/cli/u/comics/create.json b/spec/cli/u/comics/create.json
new file mode 100644 (file)
index 0000000..7b8fabe
--- /dev/null
@@ -0,0 +1,9 @@
+{\r
+  "comic": {\r
+    "title": "コミック作るテスト",\r
+    "width": 400,\r
+    "height": 200,\r
+    "visible": 3\r
+  },\r
+  "auth_token": "Qr2cveaLKqMHA8dME7CN"\r
+}
\ No newline at end of file
diff --git a/spec/cli/u/original_pictures/create.json b/spec/cli/u/original_pictures/create.json
new file mode 100644 (file)
index 0000000..b5f7c8b
--- /dev/null
@@ -0,0 +1,6 @@
+{\r
+  "original_picture": {\r
+    "file": \r
+"iVBORw0KGgoAAAANSUhEUgAAAWIAAAF7CAYAAADohYEpAAAcW0lEQVR4nO3dTW4cx7KG4ewLz0gYGgmCVsGleBEeHJ+zAQ489IArEDS4i7hL4SoIgSPBIMd9BzolF4tVWfkTmRGR+T4AAdkkm93183V0VGbW5Xq9BgCAnv/RfgIAMDuCGACUEcQAoIwgBgBlBDEAKCOI0d3lcrnydfwVQgj/+eMPhjNN5MLwNbSyhAr6ul6vF+3ngDwEMUQRvrYQyj4QxKhC8PpAINtGECMZoTsGQtkeghiHCN7xEco2EMT4qXfw3t/f9/xzbjw8PHT/mwSyLoJ4Uj1Cl6Dt5+/v30MIIXz5+rX4MQhjPQTxJKh2x7eEcQgh/PrhQ3FlTSD3RxAPSKO3S/DaQSD7QxAPgGoXW+sw3sppXxDGfRDEDhG8SHUUyISxLQSxcbQZIGUbyoSxHQSxMVS7aEWiXUEgt0EQG9ErgAneucXCOIS0QCaM5f2i/QRm1zKACV1s/frhw2kYn7lcLlfCWBYVsYJW4UvwIhVtClsI4s4kQ5jgRamUqpg2RT8EcUc1IUzoogWJQCaM69Ej7qAkgAle9EDP2AYq4oZSA/jf//rXz3//+uFDs+cD7EkN4lhlTBDX4eahjRDC8CL1uFsfq1usXV2HilhYzgG5HNgEMCygMtZDj1hISQCHQAjDDvrFeqiIBZS0IUIghGETIyn6I4grUAVjVIRxXwRxIS7GYXS1YUwQpyOIMxHAmAlh3AcX6zLkhjABjNlx8S4N44gTEcLAvtj44hAYY5yC1kSClAOJVgRGJTG+OATaFDEE8YmzEF7WhFgOVkIYo8kZW0wYlyGID6RUwff39+9uXQ6MSCqMCeJ99Ih3EMLAWznH91nPGO8RxBuEMLBP4ji/XC5XLt69RxCvEMKADEZS5KFH/F+5IUwAY1b0i+VNP6EjZ2gaIQzIrNIWApM91mhNnGDFNKAcF+7STNuayJ2kEQIhDKzRopAzZUVcEsIA3pIa0saFuwmDuDSEqYYBtDJVEBPCgCyqYhnT9IjPdnTsICGIgTj6xXWmqIhLQ/jXDx8IYSAB50mdKYI4JhbCAOTRonhv+CCedccCvVG8lBs6iEtaErQjgPYYHvrWsEFcGsIAynEOlRk2iGN4NwZgyZBBXNIX5p0ckFF7Ls14XWfIccSxHckoCVjy8PDQ9PGXeypqSBlbzJjiH4ZbBrMkhIHeWgfw9u9oBnKpmZbJHKoirpm4AbTWK3xjegZy6mw7quKBgnjmKcwSJ7jHismL2P55eXlp+rdvb28Pv9djn9OeSDNFEJ+1JDwG8ci9RUty70SxHEtn+6d1AG9pBjJhfG6IIK7tC3sKYu2PtxZOWstigdI7fPccBXLL/UqL4tzQQew9hFNDV+IEj1VMLY1yAdV6AO/Z7nPLYTx6ELsfRzzqmMOUj7bLl4T14/UMji9fv0ZDzIO956+xLXNtn5/2p62YUc/zhfuKeMRqWPPizpnWlbO3Cnkbwtr7p9R6v7aqjGlRHHMdxKP1hrcB7PWkznEU7B4CeR0YI+wrD2FMEBtUUw2HYCeI9yrgEU7sHHuBbDWMR6mC91gJ49mC2O3MutqeESFsy/Ka10GwPhmthPLIIQw9biti720JAjjOYstiphBetj9VcR8ug1hiPQmtICaA01kK49H6wWcstChmumjnfvjaGiE8lqMhYL2Hu80WwiH0eZ1n56GVdlQP7oLY43jCh4eH3RERs5zUErbbq1cYzxjCWy3HF5cWRR5zIMZda6J2pEQIfSviGYektbZtWbSqnAjhPi2KEOJtihlaFO4qYi+OqmDU69GqIITtmKFFMV0Q96iGaUO0p903nkWvKdCz3z3dVRBLtCVaowrup9UbHNXwW5a3wSi9Ylc9Yg8z6ZYgtnzwjmjdy6x5Y5YM4Zubm6rfz/X6+trssekVt+WmIvZYDUNHaZtCIoRvbm5+fvW2/tvSz6Fni2JGboIYiJH8BFLyWFrhe6ZVMGuIFV3eWxQEsZB1lUBbwp/SKtpbwO1VzdZeQ6wqtvQJWJKLIPbQllgQwnpKJ3yUtiQshZeEs0DuuYh8SYvCc1XsIoitozfsFyH8nrUKeWvEFoX5IPZUDUNfj2nQlkNK0l7bwsOtlTyGsfkgBnK1DONZQnhrHcgW2m+jFWKmg9hbNWzhAEW63LbErCG8tgTyMv9Asyq2mgMl3N6hwwqrH896hkbLiQSlXl5efk5C+PL1a/SkPQthAjju4eGh6SSPGZgNYm/VsDbNsNj72xbCeR3GW0s1HAthAjjuer2Gy8X1hDYzTLcmrNMeO2xxDOjCynNb9su6DZHSN9Z+3t5Y/WTohdmKGPs8BoSVNsm2RXH05ulxG8M3KuJCvaphq7OfrDobchVrSbCN860XDaMqLmcyiD31h1uHMMrlDLliW5cjjOuZDOIWJFd1an2wUZnJ2m7P6/XKJw1hhHEdc0HsqRpugVBo53q9Bk/rb3ujEcZHueBtdp25IPZEui1BCANzIogztXqnJ4SBeZkK4lnbEoQwRrFu/9ArTmcqiD2RuJ8ZF4owOs0w9tQnNjOhw0M1LHFQEbwAtqaoiK3ckJAQxix6jlCxVKyVmiKILSCEMZtlQSB6xecI4g4IYcyIMdvpTASxh/7wGvc2A/JQFceZCGIPSg4kQhiz6zXbzvsMO4IYAJQRxI1QDQM/sCDQOYK4AUIYQA6CGACUEcTCqIaB92hPxBHEgghh4Bjjio8RxAlS7k9HCAPpqIrfIogBdENVvI8gFkA1DOSjKv4HQVyJEAZs8Dy7jiCuQAgDkEAQA4NalqFM+bnly4q/v3/XfgpdmblDhzdUw7BqHajLv/cuku0Fb+zn0Q5BnIkARqnL5ZIVcNugTPndo6o2N2BznyvqEMRAY6kV6t7P7/3/o99NaS0sAWupDQF6xEAzsb5r7v/P/ZmWvw95BDHQQGqg7lXLqY9f+rspaEv0RWsCEJYbijX9WAJ4DFTEgAGt2gU5wTpCCHud1EEQA4JaVKi1AZny+5ZCeLYxxCEQxDDA4oSCErHnXxuoJb+//vnY71oK4VnRI4aa0SYUHA0L2wZizRtO6u/vbT8P23TGajgEghgN1QTOKBMKjgKxNEzX///oMUbYbrMhiCFOqsXgMYxTn+9ZGHvr66IOPeIE9/f3P//tvY/ZmvT2GaF3fOSs4sU8TATx9XrdPdO+fP3a+6m4lRtY6wtkEhfLWgfmyGG8/cJ8aE04tw2o2vUIjn6/dRCm9E09tiqAFCYqYg+W9oSXIIiNSEj9/V7DypZtWrO6GOAZQZzJUs8ytbpN+dmW9j5+H30U5+M5anmcXUcQZ7BUFefefUEDoQqkIYgLWKqKrZKYlut1UgKQy0wQM3IindSbQKur9dKPxYgCjM5MEHuh3Z6QDOG9/3e2JkHKF4A8DF8rpLUmwtl6BjVTZ1O/D1jm8VM0FXEB7ap4K3WVrZTvA+hviiButaKT1kW7s1YAbQPMKlYNH12HssBFEHv8qAEAqVwEsQTpqthaewLwrvYc9VoNh2AsiK1vrD2MKQbqzbog/MJUEMdItCdm39nAqDxXwyEYDGIPG21BewKoR4FkMIhD8DfLjvYEUEYihL1XwyEYDeKWuGiHUkeL6Usvso/5uAtiqmJoYN/aNEI1HMKkU5z//v49/PrhQ9HvPjw8RL/v+Xbw2FcawtxR5L3//PGH9lMw6WL5QIkt5Hy0+HOOnDA+C+Ajlrcvzq1DeH0T2bWjY4N9v2+9TWvO41Gq4RAmrYh7oiry6yyE9wKYfY0SpnvEsXe1nuOKS6vhBf1Ff1Iq4TXW8uhrpGo4BAcV8fV6vbS811RNvzgHlbEP2zfNlEqY/Zru9fVV+ymYZLoiXrQeVxyrjGur4TUqY9tSQniLEE4nFcKjVcMhOKiIe8mtjB8fHw+/d3d3d/g9KmObUkN4/cbMfkzXI4Q9c1ERx0jumG1lXFoNx0I6BCpja7b94NzREYjrFcJeq+EQqIjfKe0Zf/z86c1/Pz1/C58/fjr4aVhQ0opYUA2noRJO46Yi7vlu9/f379HqZ1vxbkN48fT87fAxqIp15YYwLYl8PUPYczUcgqMgjun5bnnWdshBGOvYBgQhLI8QzuOqNREbyvbl61eR2XbLY0k5a1Fw8U5PSitiHcIvLy/h9fU13NzctHxaCOnn4AghHMIgFXEvpdVwrEUBPX/++Wf0+0ftKcbCxrF98rkL4taz7XIf46g/DNteXl6qfp6w2SexXXLOwcvlcl2+qv+wIndB7HWDUxXbdFQVpwxVI4zfktoepS1Gz4HsKohTNnKrC3eSF+lgyzaMtyEcq54JY3m157DHMHYTxDkbd/Qxhyh3Fpw5IZz6mDOwNl7YW3XsIohLNihhjBx7LYqcPvLMYWwthNe8hLH5IO65IQnvudVOYX59fZ0ukHuH8NPzt/D0/C2rVeghjE0H8dkGfHx8jO4QqWClPzyHl5eXN1+lZgnjniG8BPDz04+vEM7P/zXrYWw2iFNCeO/fW1S5gF2pIbwO4MXHz5/Cx8+ffob0GcthbDKISzYYYQxLRm5T9Hxtj4+PbwJ4Cd+98fuew9hkEJ+hVQAvRgvjnq9nfZ4fhe+W1zA2F8SxjXTWE6IqBtrRDOEcHsPYXBDXIowBeT1bETUhvEjtG1thKojPqmHAI+/tCcnnf3t7K/ZYKU7WBDdTFZsKYineqmLWJR6f9zDuIfWGC5KshLGZIKYaxug8jqToVQ23DGEPLQoTQdwihC1Wxdw6CSH4qY69PM8U1lsUJoK4FYthHEMYt2UpWCw9lz3Sz0+rGvZCPYhbtySshfHZxyTCuA2LwWe1VaEZwi1ZrorVg1gbYTw+i2G3Zun59QxhDVb7xapB3OsCnceLfYSxDEshF2PhebZ4DrmLJ83YlgghhIvmHYR7j5S4u7sr+r3Yc6k5cGJ3d15wh+c6FgIuh9Ydoltsp7NqeO+86hHEsfNO667QahWxxnA1a5Vx4lRMquNC3kI4BJ3nrPE3tUI4BJvtCZUg1myMewzjEGhVzKTnRbxWfyf3At2sLYmFuYt11oKyB8JYnsdqeKvla2gZ9tYu0HnQPYgtzKDLWdm/F8IYe1qEZcsALukLW6L1ab1rEGuP1duydlBk3Gmgw7Pxa4RqeE2yetWsgo/ON422hLU+sZnWhFYoWgvjENICmTCeT20gWwxhizQKxm5BbKElUfL3tZ9bDGH83mjV8J4lkHNea6vhabUhrHmRzlJV3CWIrbUk9lgMXNoUOJMSyBpjhBdWQ/hM78z6pfUfyLkbc47YTtze7dWzp+dvSRM/MEc1fKTna5doRVgJYSvnl2qPuEUIL9+X2tGls/Ek0S+GBRKtiBDshLAlTSviFn3hnJ348fOnYarjJYyP3r0vl0t4eXlRmyKrbeZquDWJNoRHl8vl2mvKc7MgtnJxbh3co4Tykdvb25+LrMwUyIRwGzkTM1LOaauVsIX2hJnhaylqd6TVAyFH6pXeWcJpltfZ2ywhfKbXRbsmFbF2S+LscUaujG9vb8P1ep0ioGZ4jRqkWxFeQ7in5qMm1rRDeP14nsM4tV9cE1TWWxuEsDzpKtgT7faEeBBLl/Kt3k29h3EI8YPn5uZGdBaW9WBGnVYX5KiG03SriC2+g458kCxVsZR1MGuHMtWwrBZTlEc+t1roEsRWWhIjilXF61EUkgjCMcw6LM0i0SCWaksQwEBbtCLeOypqeowndjV8DftiQ9pYpLvOMptslO2Y81pmCmFtYkFMNazL0kpSo/jrr7/e/LfnMM59MyGE+2reI87ZoezMNlr1ime0hJmH7Vn6xkEI99d1HHEMO7OexoW70d3f3//898PDw89/l2zPvWBssU8IYH/MBDFg3f39/bswtqbkOZWMiiCEZYn0iGv7w9Z3qoWlMFNx4a6t+/v7N1Vyrdp9sr6YSAj71XTUhLfxh7EQOwpj77PzEPfw8PCmCl5IhXFpa0JiJAchbMfleq0b7FCzwI/FnRqbb27pLrRnjl4HfeJ0Ep8gPPeA91g81iUdnTemxxGPFsIhUBXjHzUh+vLyIh7CNe0Hb59OZ8PFukwp/WLG9I5jCdOzAGz5SUOzAl5YLZxGUdyaqF1z2PqOlVgSTzuQaU/41uvi2xHr52gLWq0J8YqYj0D/+Pzxk3oYw5/cAJY+52YMYG1FQdzr9iGatBeKxly0q98QCOAQ9Bb+YdGfiFGrWcYT29Fz/G8MIawru0csdT86bzu+pDq2EORnz5t+cV8Sb4L0gduKnTOtqmKxHvHIveGUEPb6+tfBQCiXa/kpo9WxRQjv02hLMnztxNkO8RrAe2hZ2EL7YR4EccQIF+u46OiTVAgTvrJaXbQjiCuMVA1DH+FrR+8ChiA+MFNLArpYAwIEcQFvIUx7whYqX2wRxJm8hfCZ9evxtO6yNb2PC4shPMtM0hZ9YoJ4x6zV42hvMqOyFsLr82X59wiB3POTJDPrJkcV7MfHz59Mh3DK/8c+gjiD54pxhAplVhYDGLII4o0Z38mpiu1ZwtdyAM94rrRCjziR52oYflgO3rWzEOYTWB6CeCIMY7PJS/guCGF5tCYARYQwQqAifoNqEb14C+AQCOGWqIgT0B+GJEIYWwQxQgiMnOjB+iiIUoRwPVoT/zVLW4ILdv2MErqx44UQlkEQA4JGCd8UM4Rwr5uJEsQn6A+3NVNwecSnpz4I4kYIGLYBkIoghijCdxz0hvth1EQDXsOIkRNYEMJ9EcTCPISw9Ink4TVDzvPTtzdfqEdrQtCsgcTJOJZYNbx38Xq9/2c9B2pREeONmvYEJ+HYUkYQ8aZchopYiLcQYmIH9kgcE7Ew9nae9EJFLIRKAN7ltiRKjNRXvlwuV6nHIogBdOcpjHuMEiGIAXSphrc8hXFrBDEANYTxDwQxgEM91lohjAliAAbMHsYEMUQwLAm1Zg5jghiAGbOGMUGMalTDkDRjGBPEeIdV2IC+COKJSQxUpxoG6rHWBOAUa4WMgyAGnOkZwLltKu7xWIYgRjHaEn15qIDXwU0opyOIAeM8BPCeJZQJ5HMEMYpQDbfjNXiP3N3dEcYnCGLAiNECGOkIYkBZTQBLVpotx49TFccRxIASKwEs9ZhnQU4YHyOIAUdyJ+H0nC68hGwskAnjfcysAxTkVMNPz99+fuX6+PnTz69ezoKWKfTvUREDHaUGcIv7pB2FcYuq+fHx8bQyXn4OE1bEnz9+4up0AqoWWanHXWnlW2NdNUtWzikhy3H2wzRBvD0RCOQfep/0M9KsgktIBjIVb5ppgvgIYXyMaqVOzpu9lRBeI4z7mSKIz06G2cPYYgh4l3sxziqp6vgojAnpH6a4WPf0/G36sEUfowTw1sfPn6ov6hG6x6aoiIHWcq85eArhBeuLtDNNED89f+MdGU2UjAn2qveY5FlM0ZpYS5n9A6TyfDGuhkSr4uhxZyRWEVsPtu1BQ3WMGt5HREigOpYzXUUM1Jg9fPdIVcczh3p2EF+v18vlcrnufc/bgh60KZCDED42c4hKmOZiXYynNw/YNmMIo15REF+v18vR96guMaKzatj7aAjoKq6ICWPMIOWiHAGMWlNcrOu5ODbGQD8YPVX1iKmKMRpW5YOG6oo4NooC6Kl3gFINQyr71EZN0C6AFKpYeNc0iGlPoCUCGKMQCWJ6xeitZwDvtSBoS8yjx7HWZdSEtxl3sEsrgAneefVYz1ysNRGrigFvCF70JFoR565D8fz0jTnqSJZ6F2RAUuy4+/L7byJ/Y4oJHRgfAYzepEI4hAajJnJbFAxjQ4pYVUIIo5Ve1yS6jiM+GkFBGCOGIWqwRrIaDqFREJcMZyOMUYJqGK30LABMrUdsMYwZB62LlgR6e376Fs0i6Wo4hIZBXDrJQyuMOantIYTR25I/vQswUxXxQjqMU4bIWazGZ0ZfGD2tq2CNT8FNg9jb1Gdm/9nAQuzoaV2EnRVtLdoSIShXxD3DuHTiSGo4MzFFBpUwetqGcI/JG3uaT+g4W6+45zoUKbf9LnkuI4dwrzfL1CqXahhScirh1rrMrCtZPH7ZSNIbKCWMcx8P9Zi+jF72zv+z469lNRxCx9ZE6aJALS6iSYUnIdwPIQwJJXnSOoRDaFQRS986qcXiQKWVMeHbHxdRUSt2rlsYOFAUxNJBq7Ve8VmobnceIdwfIYxaNSHcoxoOIYRfuPHnMYJX1+PjI/sAVTyEcAiGlsHkLh42tTwY//2//9fssQEvIRyC0Zl1e5j5NpazEKYaRo2avOgdwiE4CuIQCONZ8MkIpc4W7AkhXg1rhHAIjVsTsRe1VxGltCe4vZJ/KS0J9jFS5RRoFkZI7KkKYq13D8J4XFTDSCX9CVkrz0II4fLl99/URk0cVUas79Df0cwi6YMzVg2v9zv7FjElIWyxJbFw1SPeomc8DkIYqaRD2AIzw9dKtVqTAvKsDFereQPnONNTut+sDVXb4z6IF/SNcUbiExTHWT8S+8t6JbwYJohRrscawKm94VYk21hHj0VA15FuNaaEsIVqOATlHvHRRvDyLja6HgdpyxBexpT2upbANYt8rfaRpxAOYbCKmH6xTT17w9phyDF4rvU+8hbCIRgeNVFTFWufjJ5o3ppIuhq2tN97V+PW9doeHkM4BAMV8Zfff2tSMbGEZR2LB2uM5cCbvUrusW+8BvBCPYh7mf1k2GP1Rp25IxMsh/Cal+fpjfcQDsFIa6LnRTs+Lv5gNYRzsC/ndnd3N0QIh2AkiGNajaCY+STWvlGihFn3HdIDOAQfx3IIhloTsV5xy0XjZ2tZjFAJS0s9qVmQSFduUeYlhEMwFMRnlp1AIJdLCWEPB69UNZx7Ysd+npBup+RTsYfjeE119bU9KSMoehz0owWyZgiXzKo72v4epr0SynVq94+3EA7BaRCH0Pdg9x7KFirh2iVPJfSesUkg56vZRx4DeGEuiEPIm4nV+2D3FMrPT9/MXFXWXGtCe8o8gRw3YwW8ZbJHvGzYlEBu3TveGu1q/QgHcYx2CC/PYdYwbrH9RzxmTVbEa6Wz7mY98BdWKuG13u0JyavsvdbLaHncWnhTqjFiAC/MB3EIdSfBjIFsMYRD6BvEOaFTsy2sLHY/upFDOASjrYmtnFbF1kwfC0cb5F6q5xvR+nEIZVmjH6drLoJ4URrIvfvIvfWq/jzQ/DRQUzDgrdGP0y0XrYkjs/ePvc00aj1ywlJLhjDOo31sanMdxIvZAtnrTKOz/VSzPyyF8NrsgWzhuPNgiCBeyz3wPYVx6VVvSydDizC2GsI5egS29W0wM1c94hS5fTov/WNvbYgeRgjghZfniTaGq4i3SioNjVCWHONp/aSWqIpHCmFg+CAOYY4+nbfQKV3ciSF6GNEUQbwYMZA9B06r/eF5m2BO5u/QIWm0E9T762nx/L1vE8xpqop4zXN1PFrYSO2L0bYL5jFtEC88BfLIQVOzH0beLpjD9EG8RyucZw+Uku0++zbDGAhimJITxoQwRjHchA74RrhiRlONmgAAiwhiAFBGEAOAMoIYAJQRxACgjCAGAGUEMQAoI4gBQBlBDADKCGIAUEYQA4AyghgAlBHEAKCMIAYAZQQxACgjiAFAGUEMAMoIYgBQRhADgDKCGACUEcQAoIwgBgBlBDEAKCOIAUAZQQwAyghiAFBGEAOAMoIYAJQRxACgjCAGAGUEMQAoI4gBQBlBDADKCGIAUEYQA4AyghgAlP0/Bxl7hN5Zu0EAAAAASUVORK5CYII="  },\r
+  "auth_token": "Qr2cveaLKqMHA8dME7CN"\r
+}
\ No newline at end of file
diff --git a/spec/cli/u/panels/create.json b/spec/cli/u/panels/create.json
new file mode 100644 (file)
index 0000000..9eba8b6
--- /dev/null
@@ -0,0 +1,23 @@
+{\r
+  "panel": {\r
+    "width": 400,\r
+    "height": 200,\r
+    "border": 1,\r
+    "x": 0,\r
+    "y": 0,\r
+    "z": 1,\r
+    "publish": 1,\r
+    "panel_pictures_attributes": {\r
+      "new1": {\r
+        "resource_picture_id": 3,\r
+        "x": 10,\r
+        "y": 135,\r
+        "z": 3,\r
+        "t": 0,\r
+        "width": 100,\r
+        "height": 103\r
+      }\r
+    }\r
+  },\r
+  "auth_token": "Qr2cveaLKqMHA8dME7CN"\r
+}
\ No newline at end of file
diff --git a/spec/cli/u/stories/create.json b/spec/cli/u/stories/create.json
new file mode 100644 (file)
index 0000000..577fff4
--- /dev/null
@@ -0,0 +1,7 @@
+{\r
+  "story": {\r
+    "comic_id": 1,\r
+    "panel_id": 1\r
+  },\r
+  "auth_token": "Qr2cveaLKqMHA8dME7CN"\r
+}
\ No newline at end of file
diff --git a/spec/cli/update.rb b/spec/cli/update.rb
new file mode 100644 (file)
index 0000000..8e19b43
--- /dev/null
@@ -0,0 +1,14 @@
+if ARGV.size < 2\r
+  puts 'update.rb subdir controller {filename=update.json}'\r
+  exit\r
+end\r
+domain = 'http://localhost:3000'\r
+user = ARGV[0].to_s\r
+ctl = ARGV[1]\r
+f = ARGV[2] ? ARGV[2].to_s+'_update' : 'update'\r
+path = File.expand_path(File.dirname(__FILE__))\r
+filename = path + "/#{user}/#{ctl}/#{f}.json"\r
+\r
+cmd = "curl -d @#{filename} #{domain}/#{ctl}.json  -X PUT -H \"Content-Type: application/json\""\r
+puts cmd\r
+exec cmd\r
index 07156f0..7ae248d 100644 (file)
 # -*- encoding: utf-8 -*-\r
-require 'spec_helper'
-
-describe ComicsController do
-  before do
-    Factory :admin
-    @license = Factory :license
+require 'spec_helper'\r
+\r
+describe ComicsController do\r
+  before do\r
+    Factory :admin\r
+    @license = Factory :license\r
     @user = Factory :user_yas\r
-    @author = @user.author    #ユーザ作成時に連動して作成される
-  end
-  
-  describe '一覧表示に於いて' do
-    before do
-      @comic = Factory :normal_comic, :author_id => @user.author.id
-      Comic.stub(:list).and_return([@comic, @comic, @comic])
-      sign_in @user
-    end
-    context '事前チェックする' do
-      it '与えられたpageがセットされている' do
-        get :index, :page => 5
-        assigns(:page).should eq 5
-      end
-      it '省略されると@pageに1値が入る' do
-        get :index
-        assigns(:page).should eq 1
-      end
-      it '与えられたpage_sizeがセットされている' do
-        get :index, :page_size => 15
-        assigns(:page_size).should eq 15
-      end
-      it '省略されると@page_sizeにデフォルト値が入る' do
-        get :index
+    @author = @user.author    #ユーザ作成時に連動して作成される\r
+  end\r
+  \r
+  describe '一覧表示に於いて' do\r
+    before do\r
+      @comic = Factory :comic, :author_id => @user.author.id\r
+      Comic.stub(:list).and_return([@comic, @comic, @comic])\r
+      sign_in @user\r
+    end\r
+    context '事前チェックする' do\r
+      it '与えられたpageがセットされている' do\r
+        get :index, :page => 5\r
+        assigns(:page).should eq 5\r
+      end\r
+      it '省略されると@pageに1値が入る' do\r
+        get :index\r
+        assigns(:page).should eq 1\r
+      end\r
+      it '与えられたpage_sizeがセットされている' do\r
+        get :index, :page_size => 15\r
+        assigns(:page_size).should eq 15\r
+      end\r
+      it '省略されると@page_sizeにデフォルト値が入る' do\r
+        get :index\r
+        assigns(:page_size).should eq Comic.default_page_size\r
+      end\r
+      it '最大を超えると@page_sizeにデフォルト最大値が入る' do\r
+        get :index, :page_size => 1500\r
+        assigns(:page_size).should eq Comic.max_page_size\r
+      end\r
+      it '不正な値が入ると@page_sizeにデフォルト最大値が入る' do\r
+        get :index, :page_size => 0\r
         assigns(:page_size).should eq Comic.default_page_size\r
-      end
-      it '最大を超えると@page_sizeにデフォルト最大値が入る' do
-        get :index, :page_size => 1500
-        assigns(:page_size).should eq Comic.max_page_size
-      end
-      it '不正な値が入ると@page_sizeにデフォルト最大値が入る' do
-        get :index, :page_size => 0
-        assigns(:page_size).should eq Comic.default_page_size
-      end
-    end
-    context 'つつがなく終わるとき' do
-      it 'ステータスコード200 OKを返す' do
-        get :index
-        response.should be_success 
-      end
-      it 'コミックモデルに一覧を問い合わせている' do
+      end\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it 'ステータスコード200 OKを返す' do\r
+        get :index\r
+        response.should be_success \r
+      end\r
+      it 'コミックモデルに一覧を問い合わせている' do\r
         Comic.should_receive(:list).exactly(1)\r
-        get :index
-      end
-      it '@comicsにリストを取得している' do
-        get :index
-        assigns(:comics).should have_at_least(3).items
-      end
-      context 'html形式' do
-        it 'indexテンプレートを描画する' do
-          get :index
-          response.should render_template("index")
-        end
-      end
-      context 'json形式' do
-        it 'jsonデータを返す' do
-          get :index, :format => :json
-          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
-        end
-        it 'データがリスト構造になっている' do
-          get :index, :format => :json
+        get :index\r
+      end\r
+      it '@comicsにリストを取得している' do\r
+        get :index\r
+        assigns(:comics).should have_at_least(3).items\r
+      end\r
+      context 'html形式' do\r
+        it 'indexテンプレートを描画する' do\r
+          get :index\r
+          response.should render_template("index")\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'jsonデータを返す' do\r
+          get :index, :format => :json\r
+          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
+        end\r
+        it 'データがリスト構造になっている' do\r
+          get :index, :format => :json\r
           json = JSON.parse response.body\r
-          json.should have_at_least(3).items
-        end
-        it 'リストの先頭くらいはコミックっぽいものであって欲しい' do
-          get :index, :format => :json
-          json = JSON.parse response.body
-          json.first.has_key?("title").should be_true
-        end
-      end
-    end
-    context '作家権限がないとき' do
-      before do
-        sign_out @user
-      end
-      context 'html形式' do
-        it 'ステータスコード302 Foundを返す' do
-          get :index
-          response.status.should eq 302
-        end
-        it 'サインインページへ遷移する' do
-          get :index
-          response.should redirect_to '/users/sign_in'
-        end
-      end
-      context 'json形式' do
-        it 'ステータスコード401 Unauthorizedを返す' do
-          get :index, :format => :json
-          response.status.should eq 401
-        end
-        it '応答メッセージにUnauthorizedを返す' do
+          json.should have_at_least(3).items\r
+        end\r
+        it 'リストの先頭くらいはコミックっぽいものであって欲しい' do\r
           get :index, :format => :json\r
-          response.message.should match(/Unauthorized/)
-        end
-      end
-    end
-  end
-  
-  describe '単体表示に於いて' do
-    before do
-      @comic = Factory :normal_comic, :author_id => @user.author.id
-      Comic.stub(:show).and_return(@comic)
-      sign_in @user
-    end
-    context 'つつがなく終わるとき' do
-      it 'ステータスコード200 OKを返す' do
-        get :show, :id => @comic.id
-        response.should be_success
-      end
-      it 'コミックモデルに単体取得を問い合わせている' do
+          json = JSON.parse response.body\r
+          json.first.has_key?("title").should be_true\r
+        end\r
+      end\r
+    end\r
+    context '作家権限がないとき' do\r
+      before do\r
+        sign_out @user\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          get :index\r
+          response.status.should eq 302\r
+        end\r
+        it 'サインインページへ遷移する' do\r
+          get :index\r
+          response.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード401 Unauthorizedを返す' do\r
+          get :index, :format => :json\r
+          response.status.should eq 401\r
+        end\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          get :index, :format => :json\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
+    end\r
+  end\r
+  \r
+  describe '単体表示に於いて' do\r
+    before do\r
+      @comic = Factory :comic, :author_id => @user.author.id, :title => 'normal'\r
+      Comic.stub(:show).and_return(@comic)\r
+      sign_in @user\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it 'ステータスコード200 OKを返す' do\r
+        get :show, :id => @comic.id\r
+        response.should be_success\r
+      end\r
+      it 'コミックモデルに単体取得を問い合わせている' do\r
         Comic.should_receive(:show).exactly(1)\r
-        get :show
-      end
-      it '@comicにアレを取得している' do
-        get :show, :id => @comic.id
-        assigns(:comic).id.should eq(@comic.id)
-      end
-      context 'html形式' do
-        it 'showテンプレートを描画する' do
-          get :show, :id => @comic.id
-          response.should render_template("show")
-        end
-      end
-      context 'json形式' do
-        it 'jsonデータを返す' do
-          get :show, :id => @comic.id, :format => :json
-          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
-        end
-        it 'データがアレになっている' do
-          get :show, :id => @comic.id, :format => :json
-          json = JSON.parse response.body
-          json["title"].should match(/normal/)
-        end
-      end
-    end
-    context '作家権限がないとき' do
-      before do
-        sign_out @user
-      end
-      context 'html形式' do
-        it 'ステータスコード302 Foundを返す' do
-          get :show, :id => @comic.id
-          response.status.should eq 302
-        end
-        it 'サインインページへ遷移する' do
-          get :show, :id => @comic.id
-          response.body.should redirect_to '/users/sign_in'
-        end
-      end
-      context 'json形式' do
-        it 'ステータスコード401 Unauthorizedを返す' do
-          get :show, :id => @comic.id, :format => :json
-          response.status.should eq 401
-        end
-        it '応答メッセージにUnauthorizedを返す' do
-          get :show, :id => @comic.id, :format => :json
-          response.message.should match(/Unauthorized/)
-        end
-      end
-    end
-=begin
-    context '対象コミックがないとき' do
-      context 'html形式' do
-        it '例外404 not_foundを返す' do
+        get :show\r
+      end\r
+      it '@comicにアレを取得している' do\r
+        get :show, :id => @comic.id\r
+        assigns(:comic).id.should eq(@comic.id)\r
+      end\r
+      context 'html形式' do\r
+        it 'showテンプレートを描画する' do\r
+          get :show, :id => @comic.id\r
+          response.should render_template("show")\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'jsonデータを返す' do\r
+          get :show, :id => @comic.id, :format => :json\r
+          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
+        end\r
+        it 'データがアレになっている' do\r
+          get :show, :id => @comic.id, :format => :json\r
+          json = JSON.parse response.body\r
+          json["title"].should match(/normal/)\r
+        end\r
+      end\r
+    end\r
+    context '作家権限がないとき' do\r
+      before do\r
+        sign_out @user\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          get :show, :id => @comic.id\r
+          response.status.should eq 302\r
+        end\r
+        it 'サインインページへ遷移する' do\r
+          get :show, :id => @comic.id\r
+          response.body.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード401 Unauthorizedを返す' do\r
+          get :show, :id => @comic.id, :format => :json\r
+          response.status.should eq 401\r
+        end\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          get :show, :id => @comic.id, :format => :json\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
+    end\r
+=begin\r
+    context '対象コミックがないとき' do\r
+      context 'html形式' do\r
+        it '例外404 not_foundを返す' do\r
           lambda{\r
-            get :show, :id => 0
-          }.should raise_error(ActiveRecord::RecordNotFound)
-        end
-      end
-      context 'json形式' do
-        it '例外404 not_foundを返す' do
+            get :show, :id => 0\r
+          }.should raise_error(ActiveRecord::RecordNotFound)\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it '例外404 not_foundを返す' do\r
           lambda{ \r
-            get :show, :id => 0, :format => :json
-          }.should raise_error(ActiveRecord::RecordNotFound)
-        end
-      end
-    end
-    context '非公開コミックを見ようとしたとき' do
-      context 'html形式' do
-        it '例外403 forbiddenを返す' do
-          Comic.any_instance.stub(:visible?).with(any_args()).and_return(false)
-          hidden = Factory :hidden_comic, :author_id => @author.id
+            get :show, :id => 0, :format => :json\r
+          }.should raise_error(ActiveRecord::RecordNotFound)\r
+        end\r
+      end\r
+    end\r
+    context '非公開コミックを見ようとしたとき' do\r
+      context 'html形式' do\r
+        it '例外403 forbiddenを返す' do\r
+          Comic.any_instance.stub(:visible?).with(any_args()).and_return(false)\r
+          hidden = Factory :hidden_comic, :author_id => @author.id\r
           lambda{\r
-            get :show, :id => hidden
-          }.should raise_error(ActiveRecord::Forbidden)
-        end
-      end
-      context 'json形式' do
-        it '例外403 forbiddenを返す' do
-          Comic.any_instance.stub(:visible?).with(any_args()).and_return(false)
-          hidden = Factory :hidden_comic, :author_id => @author.id
+            get :show, :id => hidden\r
+          }.should raise_error(ActiveRecord::Forbidden)\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it '例外403 forbiddenを返す' do\r
+          Comic.any_instance.stub(:visible?).with(any_args()).and_return(false)\r
+          hidden = Factory :hidden_comic, :author_id => @author.id\r
           lambda{\r
-            get :show, :id => hidden, :format => :json
-          }.should raise_error(ActiveRecord::Forbidden)
-        end
-      end
-    end
-=end
-  end
-  describe '閲覧に於いて' do
-    before do
-      @comic = Factory :normal_comic, :author_id => @user.author.id
-      Comic.stub(:show).and_return(@comic)
-      sign_in @user
-    end
-    context '事前チェックする' do
-      before do
-        Panel.stub(:count).and_return(10)
-      end
-      it '与えられたoffsetがセットされている' do
-        get :play, :id => @comic.id, :offset => 7
-        assigns(:offset).should eq 7
-      end
-      it '省略されると@offsetに0値が入る' do
-        get :play, :id => @comic.id
-        assigns(:offset).should eq 0
-      end
-      it 'コマ数以上が与えられるとコマ数-1が入る' do
-        get :play, :id => @comic.id, :offset => 10
-        assigns(:offset).should eq 9
-      end
-      it '負の値が与えられると末尾(コマ数)からさかのぼった値が入る' do
-        get :play, :id => @comic.id, :offset => -3
-        assigns(:offset).should eq 7
-      end
-      it 'コマ数以上の負の値が与えられると計算できないので0値が入る' do
-        get :play, :id => @comic.id, :offset => -13
-        assigns(:offset).should eq 0
-      end
-      it '与えられたcountがセットされている' do
-        get :play, :id => @comic.id, :count => 18
-        assigns(:panel_count).should eq 18
-      end
-      it '省略されると@countにデフォルト値が入る' do
-        get :play, :id => @comic.id
-        assigns(:panel_count).should eq Comic.default_panel_size\r
-      end
-      it '最大を超えると@countにデフォルト最大値が入る' do
-        get :play, :id => @comic.id, :count => 1500
-        assigns(:panel_count).should eq Comic.max_panel_size
-      end
-      it '不正な値が入ると@countにデフォルト最大値が入る' do
-        get :play, :id => @comic.id, :page_size => 0
-        assigns(:panel_count).should eq Comic.default_panel_size
-      end
-    end
-    context 'つつがなく終わるとき' do
-      it 'ステータスコード200 OKを返す' do
-        get :play, :id => @comic.id
-        response.should be_success
-      end
-      it 'コミックモデルに単体取得を問い合わせている' do
-        Comic.should_receive(:show).exactly(1)\r
-        get :play, :id => @comic.id
-      end
-      it '@comicにアレを取得している' do
-        get :play, :id => @comic.id
-        assigns(:comic).id.should eq(@comic.id)
-      end
-      context 'html形式' do
-        it 'playテンプレートを描画する' do
-          get :play, :id => @comic.id
-          response.should render_template("play")
-        end
-      end
-      context 'json形式' do
-        it 'jsonデータを返す' do
-          get :play, :id => @comic.id, :format => :json
-          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
-        end
-        it 'データがアレになっている' do
-          get :play, :id => @comic.id, :format => :json
-          json = JSON.parse response.body
-          json["title"].should match(/normal/)
-        end
-      end
-    end
-    context '作家権限がないとき' do
-      before do
-        sign_out @user
-      end
-      context 'html形式' do
-        it 'ステータスコード302 Foundを返す' do
-          get :play, :id => @comic.id
-          response.status.should eq 302
-        end
-        it 'サインインページへ遷移する' do
-          get :play, :id => @comic.id
-          response.body.should redirect_to '/users/sign_in'
-        end
-      end
-      context 'json形式' do
-        it 'ステータスコード401 Unauthorizedを返す' do
-          get :play, :id => @comic.id, :format => :json
-          response.status.should eq 401
-        end
-        it '応答メッセージにUnauthorizedを返す' do
-          get :play, :id => @comic.id, :format => :json
-          response.message.should match(/Unauthorized/)
-        end
-      end
-    end
-  end
-
-  describe 'コミック数取得に於いて' do
-    before do
-      Comic.should_receive(:visible_count).and_return(3)
-#      sign_in @user
-    end
-    context 'つつがなく終わるとき' do
-      it 'ステータスコード200 OKを返す' do
-        get :count, :format => :json
-        response.should be_success 
-      end
-      context 'json形式' do
-        it 'jsonデータを返す' do
-          get :count, :format => :json
-          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
-        end
-        it 'データがHash構造になっていてコミック数が1である' do
-          get :count, :format => :json
-          json = JSON.parse response.body
-          json["count"].should == 3
-        end
-      end
-    end
-  end
-
-  describe '新規作成フォーム表示に於いて' do
-    before do
-      sign_in @user
-    end
-    context 'つつがなく終わるとき' do
-      it 'ステータスコード200 OKを返す' do
-        get :new
-        response.should be_success 
-      end
-      it '@comicに新規データを用意している' do
-        get :new
-        assigns(:comic).should be_a_new(Comic)
-      end
-      it 'コミックモデルにデフォルト値補充を依頼している' do
+            get :show, :id => hidden, :format => :json\r
+          }.should raise_error(ActiveRecord::Forbidden)\r
+        end\r
+      end\r
+    end\r
+=end\r
+  end\r
+  describe 'コミック数取得に於いて' do\r
+    before do\r
+      Comic.should_receive(:visible_count).and_return(3)\r
+#      sign_in @user\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it 'ステータスコード200 OKを返す' do\r
+        get :count, :format => :json\r
+        response.should be_success \r
+      end\r
+      context 'json形式' do\r
+        it 'jsonデータを返す' do\r
+          get :count, :format => :json\r
+          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
+        end\r
+        it 'データがHash構造になっていてコミック数が1である' do\r
+          get :count, :format => :json\r
+          json = JSON.parse response.body\r
+          json["count"].should == 3\r
+        end\r
+      end\r
+    end\r
+  end\r
+\r
+  describe '新規作成フォーム表示に於いて' do\r
+    before do\r
+      sign_in @user\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it 'ステータスコード200 OKを返す' do\r
+        get :new\r
+        response.should be_success \r
+      end\r
+      it '@comicに新規データを用意している' do\r
+        get :new\r
+        assigns(:comic).should be_a_new(Comic)\r
+      end\r
+      it 'コミックモデルにデフォルト値補充を依頼している' do\r
         Comic.any_instance.should_receive(:supply_default).exactly(1)\r
-        get :new
-      end
-      context 'html形式' do
-        it 'newテンプレートを描画する' do
-          get :new
-          response.should render_template("new")
-        end
-      end
-      context 'js形式' do
-        it 'new.jsテンプレートを描画する' do
-          get :new, :format => :js
-          response.should render_template("new")
-        end
-      end
-    end
-    context '作家権限がないとき' do
-      before do
-        sign_out @user
-      end
-      context 'html形式' do
-        it 'ステータスコード302 Foundを返す' do
-          get :new
-          response.status.should eq 302
-        end
-        it 'サインインページへ遷移する' do
-          get :new
-          response.body.should redirect_to '/users/sign_in'
-        end
-      end
-      context 'js形式' do
-        it 'ステータスコード401 Unauthorizedを返す' do
-          get :new, :format => :js
-          response.status.should eq 401
-        end
-        it '応答メッセージにUnauthorizedを返す' do
-          get :new, :format => :js
-          response.message.should match(/Unauthorized/)
-        end
-      end
-    end
-  end
-
-  describe '新規作成に於いて' do
-    before do
-      sign_in @user
-    end
-    context 'つつがなく終わるとき' do
-      it 'モデルに保存依頼する' do
-        Comic.any_instance.should_receive(:save).exactly(1)
-        post :create, :comic => Factory.attributes_for(:normal_comic)
-      end
-      it "@comicに作成されたコミックを保持していて、それがDBにある" do
-        post :create, :comic => Factory.attributes_for(:normal_comic)
-        assigns(:comic).should be_a(Comic)
-        assigns(:comic).should be_persisted
-      end
-      context 'html形式' do
-        it 'ステータスコード302 Foundを返す' do
-          Comic.any_instance.stub(:save).and_return(true)
-          post :create, :comic => Factory.attributes_for(:normal_comic)
-          response.status.should eq 302
-        end
-        it '作成されたコミックの表示ページへ遷移する' do
-#          Comic.any_instance.stub(:save).and_return(true)
-          post :create, :comic => Factory.attributes_for(:normal_comic)
-          response.should redirect_to(Comic.last)
-        end
-      end
-      context 'json形式' do
-        it 'ステータスコード200 OKを返す' do
-#          Comic.any_instance.stub(:save).and_return(true)
-          post :create, :comic => Factory.attributes_for(:normal_comic), :format => :json
-          response.should be_success 
-        end
-        it '作成されたコミックをjsonデータで返す' do
-          post :create, :comic => Factory.attributes_for(:normal_comic), :format => :json
-          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
-        end
-        it 'データがアレになっている' do
-          post :create, :comic => Factory.attributes_for(:normal_comic), :format => :json
-          json = JSON.parse response.body
-          json["title"].should match(/normal/)
-        end
-      end
-    end
-    context '作家権限がないとき' do
-      before do
-        sign_out @user
-      end
-      context 'html形式' do
-        it 'ステータスコード302 Foundを返す' do
-          post :create, :comic => Factory.attributes_for(:normal_comic)
-          response.status.should eq 302
-        end
-        it 'サインインページへ遷移する' do
-          post :create, :comic => Factory.attributes_for(:normal_comic)
-          response.body.should redirect_to '/users/sign_in'
-        end
-      end
-      context 'json形式' do
-        it 'ステータスコード401 Unauthorizedを返す' do
-          post :create, :comic => Factory.attributes_for(:normal_comic), :format => :json
-          response.status.should eq 401
-        end
-        it '応答メッセージにUnauthorizedを返す' do
-          post :create, :comic => Factory.attributes_for(:normal_comic), :format => :json
-          response.message.should match(/Unauthorized/)
-        end
-      end
-    end
-    context '検証、保存に失敗した' do
-      before do
-        Comic.any_instance.stub(:save).and_return(false)
-      end
-      it "未保存のコミックを保持している" do
-        post :create, :comic => {}
-        assigns(:comic).should be_a_new(Comic)
-      end
-      context 'html形式' do
-        it 'ステータスコード200 OKを返す' do
-          post :create, :comic => {}
-          response.status.should eq 200
-        end
-        it '新規ページを描画する' do
-          post :create, :comic => {}
-          response.should render_template("new")
-        end
-      end
-      context 'json形式' do
-        it 'ステータスコード422 unprocessable_entity を返す' do
-          post :create, :comic => {}, :format => :json
-          response.status.should eq 422
-        end
-        it '応答メッセージUnprocessable Entityを返す' do
-          post :create, :comic => {}, :format => :json
-          response.message.should match(/Unprocessable/)
-        end
-      end
-    end
-  end
-
-  describe '編集フォーム表示に於いて' do
-    before do
-      @comic = Factory :normal_comic, :author_id => @user.author.id
-      sign_in @user
-      Comic.stub(:show).and_return(@comic)
-    end
-    context 'つつがなく終わるとき' do
-      it 'ステータスコード200 OKを返す' do
-        get :edit, :id => @comic.id
-        response.should be_success 
-      end
-      it 'コミックモデルに単体取得を問い合わせている' do
+        get :new\r
+      end\r
+      context 'html形式' do\r
+        it 'newテンプレートを描画する' do\r
+          get :new\r
+          response.should render_template("new")\r
+        end\r
+      end\r
+      context 'js形式' do\r
+        it 'new.jsテンプレートを描画する' do\r
+          get :new, :format => :js\r
+          response.should render_template("new")\r
+        end\r
+      end\r
+    end\r
+    context '作家権限がないとき' do\r
+      before do\r
+        sign_out @user\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          get :new\r
+          response.status.should eq 302\r
+        end\r
+        it 'サインインページへ遷移する' do\r
+          get :new\r
+          response.body.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'js形式' do\r
+        it 'ステータスコード401 Unauthorizedを返す' do\r
+          get :new, :format => :js\r
+          response.status.should eq 401\r
+        end\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          get :new, :format => :js\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
+    end\r
+  end\r
+\r
+  describe '新規作成に於いて' do\r
+    before do\r
+      sign_in @user\r
+      @attr = Factory.attributes_for(:comic, :author_id => @author.id, :title => 'normal')\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it 'モデルに保存依頼する' do\r
+        Comic.any_instance.should_receive(:save).exactly(1)\r
+        post :create, :comic => @attr\r
+      end\r
+      it "@comicに作成されたコミックを保持していて、それがDBにある" do\r
+        post :create, :comic => @attr\r
+        assigns(:comic).should be_a(Comic)\r
+        assigns(:comic).should be_persisted\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          Comic.any_instance.stub(:save).and_return(true)\r
+          post :create, :comic => @attr\r
+          response.status.should eq 302\r
+        end\r
+        it '作成されたコミックの表示ページへ遷移する' do\r
+#          Comic.any_instance.stub(:save).and_return(true)\r
+          post :create, :comic => @attr\r
+          response.should redirect_to(Comic.last)\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+#          Comic.any_instance.stub(:save).and_return(true)\r
+          post :create, :comic => @attr, :format => :json\r
+          response.should be_success \r
+        end\r
+        it '作成されたコミックをjsonデータで返す' do\r
+          post :create, :comic => @attr, :format => :json\r
+          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
+        end\r
+        it 'データがアレになっている' do\r
+          post :create, :comic => @attr, :format => :json\r
+          json = JSON.parse response.body\r
+          json["title"].should match(/normal/)\r
+        end\r
+      end\r
+    end\r
+    context '作家権限がないとき' do\r
+      before do\r
+        sign_out @user\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          post :create, :comic => @attr\r
+          response.status.should eq 302\r
+        end\r
+        it 'サインインページへ遷移する' do\r
+          post :create, :comic => @attr\r
+          response.body.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード401 Unauthorizedを返す' do\r
+          post :create, :comic => @attr, :format => :json\r
+          response.status.should eq 401\r
+        end\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          post :create, :comic => @attr, :format => :json\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
+    end\r
+    context '検証、保存に失敗した' do\r
+      before do\r
+        Comic.any_instance.stub(:save).and_return(false)\r
+      end\r
+      it "未保存のコミックを保持している" do\r
+        post :create, :comic => {}\r
+        assigns(:comic).should be_a_new(Comic)\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          post :create, :comic => {}\r
+          response.status.should eq 200\r
+        end\r
+        it '新規ページを描画する' do\r
+          post :create, :comic => {}\r
+          response.should render_template("new")\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード422 unprocessable_entity を返す' do\r
+          post :create, :comic => {}, :format => :json\r
+          response.status.should eq 422\r
+        end\r
+        it '応答メッセージUnprocessable Entityを返す' do\r
+          post :create, :comic => {}, :format => :json\r
+          response.message.should match(/Unprocessable/)\r
+        end\r
+      end\r
+    end\r
+  end\r
+\r
+  describe '編集フォーム表示に於いて' do\r
+    before do\r
+      @comic = Factory :comic, :author_id => @user.author.id\r
+      sign_in @user\r
+      Comic.stub(:show).and_return(@comic)\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it 'ステータスコード200 OKを返す' do\r
+        get :edit, :id => @comic.id\r
+        response.should be_success \r
+      end\r
+      it 'コミックモデルに単体取得を問い合わせている' do\r
         Comic.should_receive(:show).exactly(1)\r
-        get :edit, :id => @comic.id
-      end
-      it '@comicにデータを用意している' do
-        get :edit, :id => @comic.id
-        assigns(:comic).should eq @comic
-      end
-      context 'html形式' do
-        it 'editテンプレートを描画する' do
-          get :edit, :id => @comic.id
-          response.should render_template("edit")
-        end
-      end
-      context 'js形式' do
-        it 'edit.jsテンプレートを描画する' do
-          get :edit, :id => @comic.id, :format => :js
-          response.should render_template("edit")
-        end
-      end
-    end
-    context '作家権限がないとき' do
-      before do
-        sign_out @user
-      end
-      context 'html形式' do
-        it 'ステータスコード302 Foundを返す' do
-          get :edit, :id => @comic.id
-          response.status.should eq 302
-        end
-        it 'サインインページへ遷移する' do
-          get :edit, :id => @comic.id
-          response.body.should redirect_to '/users/sign_in'
-        end
-      end
-      context 'js形式' do
-        it 'ステータスコード401 Unauthorizedを返す' do
-          get :edit, :id => @comic.id, :format => :js
-          response.status.should eq 401
-        end
-        it '応答メッセージにUnauthorizedを返す' do
-          get :edit, :id => @comic.id, :format => :js
-          response.message.should match(/Unauthorized/)
-        end
-      end
-    end
-  end
-
-  describe '更新に於いて' do
+        get :edit, :id => @comic.id\r
+      end\r
+      it '@comicにデータを用意している' do\r
+        get :edit, :id => @comic.id\r
+        assigns(:comic).should eq @comic\r
+      end\r
+      context 'html形式' do\r
+        it 'editテンプレートを描画する' do\r
+          get :edit, :id => @comic.id\r
+          response.should render_template("edit")\r
+        end\r
+      end\r
+      context 'js形式' do\r
+        it 'edit.jsテンプレートを描画する' do\r
+          get :edit, :id => @comic.id, :format => :js\r
+          response.should render_template("edit")\r
+        end\r
+      end\r
+    end\r
+    context '作家権限がないとき' do\r
+      before do\r
+        sign_out @user\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          get :edit, :id => @comic.id\r
+          response.status.should eq 302\r
+        end\r
+        it 'サインインページへ遷移する' do\r
+          get :edit, :id => @comic.id\r
+          response.body.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'js形式' do\r
+        it 'ステータスコード401 Unauthorizedを返す' do\r
+          get :edit, :id => @comic.id, :format => :js\r
+          response.status.should eq 401\r
+        end\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          get :edit, :id => @comic.id, :format => :js\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
+    end\r
+  end\r
+\r
+  describe '更新に於いて' do\r
     before do\r
-      @comic = Factory :normal_comic, :author => @author
-      sign_in @user
-    end
-    context '事前チェックしておく' do
-      it 'コミックモデルに単体取得を問い合わせている' do
+      @comic = Factory :comic, :author => @author\r
+      @attr = Factory.attributes_for(:comic, :author_id => @author.id, :title => 'updated title', :visible => 0)\r
+      sign_in @user\r
+    end\r
+    context '事前チェックしておく' do\r
+      it 'コミックモデルに単体取得を問い合わせている' do\r
         Comic.stub(:show).with(any_args()).and_return @comic\r
         Comic.should_receive(:show).exactly(1)\r
-        put :update, :id => @comic.id, :comic => Factory.attributes_for(:normal_comic)
-      end
-      it 'モデルに更新を依頼する' do
-        Comic.any_instance.should_receive(:update_attributes).with(any_args)
-        put :update, :id => @comic.id, :comic => Factory.attributes_for(:normal_comic)
-      end
-      it '@comicにアレを取得している' do
-        put :update, :id => @comic.id, :comic => Factory.attributes_for(:normal_comic)
-        assigns(:comic).id.should eq(@comic.id)
-      end
-    end
-    context 'つつがなく終わるとき' do
+        put :update, :id => @comic.id, :comic => @attr\r
+      end\r
+      it 'モデルに更新を依頼する' do\r
+        Comic.any_instance.should_receive(:update_attributes).with(any_args)\r
+        put :update, :id => @comic.id, :comic => @attr\r
+      end\r
+      it '@comicにアレを取得している' do\r
+        put :update, :id => @comic.id, :comic => @attr\r
+        assigns(:comic).id.should eq(@comic.id)\r
+      end\r
+    end\r
+    context 'つつがなく終わるとき' do\r
       it '更新される' do\r
-        put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic)\r
-        Comic.find(@comic.id).visible.should eq 0
-      end
-      context 'html形式' do
-        it 'ステータスコード302 Foundを返す' do
-          Comic.any_instance.stub(:update_attributes).with(any_args()).and_return(true)
-          put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic)
-          response.status.should eq 302
-        end
-        it '更新されたコミックの表示ページへ遷移する' do
-          put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic)
-          response.should redirect_to(@comic)
-        end
-      end
-      context 'json形式' do
-        it 'ステータスコード200 OKを返す' do
-          Comic.any_instance.stub(:update_attributes).with(any_args()).and_return(true)
-          put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic), :format => :json
-          response.should be_success 
-        end
-        it 'ページ本体は特に返さない' do
-          Comic.any_instance.stub(:update_attributes).with(any_args()).and_return(true)
-          put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic), :format => :json
-          response.body.should match /./
-        end
-      end
-    end
-    context '作家権限がないとき' do
-      before do
-        sign_out @user
-      end
-      it 'ステータスコード302 Foundを返す' do
-        put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic)
-        response.status.should eq 302
-      end
-      context 'html形式' do
-        it 'サインインページへ遷移する' do
-          put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic)
-          response.body.should redirect_to '/users/sign_in'
-        end
-      end
-      context 'json形式' do
-        it '応答メッセージにUnauthorizedを返す' do
-          put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic), :format => :json
-          response.message.should match(/Unauthorized/)
-        end
-      end
-    end
-    context '検証、保存に失敗したとき' do
-      before do
-        Comic.any_instance.stub(:update_attributes).and_return(false)
-      end
-      context 'html形式' do
-        it 'ステータスコード200 Okを返す' do
-          put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic)
-          response.status.should eq 200
-        end
-        it '編集ページを描画する' do
-          put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic)
-          response.should render_template("edit")
-        end
-      end
-      context 'json形式' do
-        it 'ステータスコード422 unprocessable_entity を返す' do
-          Comic.any_instance.stub(:update_attributes).and_return(false)
-          put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic), :format => :json
-          response.status.should eq 422
-        end
-        it '応答メッセージUnprocessable Entityを返す' do
-          put :update, :id => @comic.id, :comic => Factory.attributes_for(:hidden_comic), :format => :json
-          response.message.should match(/Unprocessable/)
-        end
-      end
-    end
-  end
-
-
-end
+        put :update, :id => @comic.id, :comic => @attr\r
+        Comic.find(@comic.id).visible.should eq 0\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          Comic.any_instance.stub(:update_attributes).with(any_args()).and_return(true)\r
+          put :update, :id => @comic.id, :comic => @attr\r
+          response.status.should eq 302\r
+        end\r
+        it '更新されたコミックの表示ページへ遷移する' do\r
+          put :update, :id => @comic.id, :comic => @attr\r
+          response.should redirect_to(@comic)\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          Comic.any_instance.stub(:update_attributes).with(any_args()).and_return(true)\r
+          put :update, :id => @comic.id, :comic => @attr, :format => :json\r
+          response.should be_success \r
+        end\r
+        it 'ページ本体は特に返さない' do\r
+          Comic.any_instance.stub(:update_attributes).with(any_args()).and_return(true)\r
+          put :update, :id => @comic.id, :comic => @attr, :format => :json\r
+          response.body.should match /./\r
+        end\r
+      end\r
+    end\r
+    context '作家権限がないとき' do\r
+      before do\r
+        sign_out @user\r
+      end\r
+      it 'ステータスコード302 Foundを返す' do\r
+        put :update, :id => @comic.id, :comic => @attr\r
+        response.status.should eq 302\r
+      end\r
+      context 'html形式' do\r
+        it 'サインインページへ遷移する' do\r
+          put :update, :id => @comic.id, :comic => @attr\r
+          response.body.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          put :update, :id => @comic.id, :comic => @attr, :format => :json\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
+    end\r
+    context '検証、保存に失敗したとき' do\r
+      before do\r
+        Comic.any_instance.stub(:update_attributes).and_return(false)\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード200 Okを返す' do\r
+          put :update, :id => @comic.id, :comic => @attr\r
+          response.status.should eq 200\r
+        end\r
+        it '編集ページを描画する' do\r
+          put :update, :id => @comic.id, :comic => @attr\r
+          response.should render_template("edit")\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード422 unprocessable_entity を返す' do\r
+          Comic.any_instance.stub(:update_attributes).and_return(false)\r
+          put :update, :id => @comic.id, :comic => @attr, :format => :json\r
+          response.status.should eq 422\r
+        end\r
+        it '応答メッセージUnprocessable Entityを返す' do\r
+          put :update, :id => @comic.id, :comic => @attr, :format => :json\r
+          response.message.should match(/Unprocessable/)\r
+        end\r
+      end\r
+    end\r
+  end\r
+\r
+\r
+end\r
index 9359603..4eb1e8d 100644 (file)
@@ -592,7 +592,7 @@ describe OriginalPicturesController do
   describe '更新に於いて' do
     before do
       @pic = Factory :original_picture, :artist_id => @artist.id , :license_id => @license.id
-      OriginalPicture.stub(:show).with(any_args()).and_return(@pic)
+      OriginalPicture.stub(:edit).with(any_args()).and_return(@pic)
       sign_in @user
     end
     context '事前チェックしておく' do
@@ -600,7 +600,7 @@ describe OriginalPicturesController do
         OriginalPicture.any_instance.stub(:store).with(any_args()).and_return(true)
       end
       it '原画モデルに単体取得を問い合わせている' do
-        OriginalPicture.should_receive(:show).exactly(1)\r
+        OriginalPicture.should_receive(:edit).exactly(1)\r
         put :update, :id => @pic.id, :original_picture => Factory.attributes_for(:original_picture)
       end
       it 'モデルに更新を依頼する' do
index 8665c64..5e8d308 100644 (file)
@@ -9,11 +9,13 @@ describe PanelPicturesController do
     @user = Factory( :user_yas)
     @author = @user.author
     @artist = Factory :artist_yas, :author_id => @author.id
+    @op = Factory :original_picture, :artist_id => @artist.id , :license_id => @license.id
+    @rp = Factory :resource_picture, :artist_id => @artist.id , :license_id => @license.id, :original_picture_id => @op.id
   end
 
   describe '一覧表示に於いて' do
     before do
-      @pp = Factory :panel_picture
+      @pp = Factory :panel_picture, :resource_picture_id => @rp.id
       sign_in @user
       PanelPicture.stub(:list).and_return([@pp, @pp, @pp])
     end
index e7c058e..ff4c090 100644 (file)
@@ -1,18 +1,17 @@
 # -*- encoding: utf-8 -*-\r
 require 'spec_helper'\r
-\r
+#コマ\r
 describe PanelsController do\r
   before do\r
     Factory :admin\r
-    @license = Factory :license
+    @license = Factory :license\r
     @user = Factory :user_yas\r
     @author = @user.author    #ユーザ作成時に連動して作成される\r
-    @comic = Factory :comic, :author_id => @author.id\r
   end\r
   \r
   describe '一覧表示に於いて' do\r
     before do\r
-      @panel = Factory :panel, :author_id => @author.id, :comic_id => @comic.id\r
+      @panel = Factory :panel, :author_id => @author.id\r
       Panel.stub(:list).and_return([@panel, @panel, @panel])\r
       sign_in @user\r
     end\r
@@ -74,7 +73,7 @@ describe PanelsController do
         it 'リストの先頭くらいはコマっぽいものであって欲しい' do\r
           get :index, :format => :json\r
           json = JSON.parse response.body\r
-          json.first.has_key?("comic_id").should be_true\r
+          json.first.has_key?("border").should be_true\r
         end\r
       end\r
     end\r
@@ -107,7 +106,7 @@ describe PanelsController do
   \r
   describe '単体表示に於いて' do\r
     before do\r
-      @panel = Factory :panel, :author_id => @user.author.id, :comic_id => @comic.id\r
+      @panel = Factory :panel, :author_id => @user.author.id\r
       Panel.stub(:show).and_return(@panel)\r
       sign_in @user\r
     end\r
@@ -290,7 +289,8 @@ describe PanelsController do
   \r
   describe '新規作成に於いて' do\r
     before do\r
-      @panel = Factory :panel, :author_id => @user.author.id, :comic_id => @comic.id\r
+      @panel = Factory :panel, :author_id => @user.author.id\r
+      @attr = Factory.attributes_for(:panel, :author_id => @author.id)\r
       sign_in @user\r
     end\r
     context '事前チェックする' do\r
@@ -299,55 +299,63 @@ describe PanelsController do
         Panel.stub(:count).and_return(10)\r
       end\r
       it 'panelがパラメータにあれば、展開する' do\r
-        post :create, :panel => Factory.attributes_for(:panel, :comic_id => @comic.id)\r
+        post :create, :panel => @attr\r
         assigns(:prm)['border'].to_i.should eq @panel.border\r
       end\r
       it 'jsonがパラメータにあれば、展開する' do\r
-        post :create, :json => Factory.attributes_for(:panel, :comic_id => @comic.id, :border => 4).to_json\r
+        post :create, :json => Factory.attributes_for(:panel, :border => 4).to_json\r
         assigns(:prm)['border'].to_i.should eq 4\r
       end\r
       it 'panel・json両パラメータがあれば、panelを優先して展開する' do\r
         post :create, {\r
-          :panel => Factory.attributes_for(:panel, :comic_id => @comic.id), \r
-          :json => Factory.attributes_for(:panel, :comic_id => @comic.id, :border => 4).to_json\r
+          :panel => Factory.attributes_for(:panel), \r
+          :json => Factory.attributes_for(:panel, :border => 4).to_json\r
         }\r
         assigns(:prm)['border'].to_i.should eq @panel.border\r
       end\r
     end\r
     context 'つつがなく終わるとき' do\r
+      it 'コマモデルにデフォルト値補充を依頼している' do\r
+        Panel.any_instance.should_receive(:supply_default).exactly(1)\r
+        post :create, :panel => @attr\r
+      end\r
+      it 'コマモデルに上書き補充を依頼している' do\r
+        Panel.any_instance.should_receive(:overwrite).exactly(1)\r
+        post :create, :panel => @attr\r
+      end\r
       it 'モデルに保存依頼する' do\r
         Panel.any_instance.should_receive(:store).exactly(1)\r
-        post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id)\r
+        post :create, :panel => @attr\r
       end\r
       it "@panelに作成されたコマを保持していて、それがDBにある" do\r
-        post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id)\r
+        post :create, :panel => @attr\r
         assigns(:panel).should be_a(Panel)\r
         assigns(:panel).should be_persisted\r
       end\r
       context 'html形式' do\r
         it 'ステータスコード302 Foundを返す' do\r
           Panel.any_instance.stub(:store).and_return(true)\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id)\r
+          post :create, :panel => @attr\r
           response.status.should eq 302\r
         end\r
         it '作成されたコマの表示ページへ遷移する' do\r
 #          Panel.any_instance.stub(:store).and_return(true)\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id)\r
+          post :create, :panel => @attr\r
           response.should redirect_to(Panel.last)\r
         end\r
       end\r
       context 'json形式' do\r
         it 'ステータスコード200 OKを返す' do\r
 #          Panel.any_instance.stub(:store).and_return(true)\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id), :format => :json\r
+          post :create, :panel => @attr, :format => :json\r
           response.should be_success \r
         end\r
         it '作成されたコマをjsonデータで返す' do\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id), :format => :json\r
+          post :create, :panel => @attr, :format => :json\r
           lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
         end\r
         it 'データがアレになっている' do\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id), :format => :json\r
+          post :create, :panel => @attr, :format => :json\r
           json = JSON.parse response.body\r
           json["width"].should eq @panel.width\r
         end\r
@@ -359,50 +367,50 @@ describe PanelsController do
       end\r
       context 'html形式' do\r
         it 'ステータスコード302 Foundを返す' do\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id)\r
+          post :create, :panel => @attr\r
           response.status.should eq 302\r
         end\r
         it 'サインインページへ遷移する' do\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id)\r
+          post :create, :panel => @attr\r
           response.body.should redirect_to '/users/sign_in'\r
         end\r
       end\r
       context 'json形式' do\r
         it 'ステータスコード401 Unauthorizedを返す' do\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id), :format => :json\r
+          post :create, :panel => @attr, :format => :json\r
           response.status.should eq 401\r
         end\r
         it '応答メッセージにUnauthorizedを返す' do\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id), :format => :json\r
+          post :create, :panel => @attr, :format => :json\r
           response.message.should match(/Unauthorized/)\r
         end\r
       end\r
     end\r
     context '検証、保存に失敗した' do\r
       before do\r
-        Panel.any_instance.stub(:save).and_return(false)\r
+        Panel.any_instance.stub(:store).and_return(false)\r
       end\r
       it "未保存のコマを保持している" do\r
-        post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id)\r
+        post :create, :panel => @attr\r
         assigns(:panel).should be_a_new(Panel)\r
       end\r
       context 'html形式' do\r
         it 'ステータスコード200 OKを返す' do\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id)\r
+          post :create, :panel => @attr\r
           response.status.should eq 200\r
         end\r
         it '新規ページを描画する' do\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id)\r
+          post :create, :panel => @attr\r
           response.should render_template("new")\r
         end\r
       end\r
       context 'json形式' do\r
         it 'ステータスコード422 unprocessable_entity を返す' do\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id), :format => :json\r
+          post :create, :panel => @attr, :format => :json\r
           response.status.should eq 422\r
         end\r
         it '応答メッセージUnprocessable Entityを返す' do\r
-          post :create, :panel => Factory.attributes_for(:panel, :author_id => @author.id), :format => :json\r
+          post :create, :panel => @attr, :format => :json\r
           response.message.should match(/Unprocessable/)\r
         end\r
       end\r
@@ -411,7 +419,7 @@ describe PanelsController do
 \r
   describe '編集フォーム表示に於いて' do\r
     before do\r
-      @panel = Factory :panel, :author_id => @author.id, :comic_id => @comic.id\r
+      @panel = Factory :panel, :author_id => @author.id\r
       sign_in @user\r
       Panel.stub(:show).and_return(@panel)\r
     end\r
@@ -468,4 +476,198 @@ describe PanelsController do
     end\r
   end\r
 \r
+  describe '更新に於いて' do\r
+    before do\r
+      @panel = Factory :panel, :author_id => @user.author.id\r
+      @attr = Factory.attributes_for(:panel, :author_id => @author.id)\r
+      sign_in @user\r
+    end\r
+    context '事前チェックする' do\r
+      before do\r
+        controller\r
+        Panel.stub(:count).and_return(10)\r
+      end\r
+      it 'panelがパラメータにあれば、展開する' do\r
+        put :update, :id => @panel.id, :panel => @attr\r
+        assigns(:prm)['border'].to_i.should eq @panel.border\r
+      end\r
+      it 'jsonがパラメータにあれば、展開する' do\r
+        put :update, :id => @panel.id, :json => Factory.attributes_for(:panel, :border => 4).to_json\r
+        assigns(:prm)['border'].to_i.should eq 4\r
+      end\r
+      it 'panel・json両パラメータがあれば、panelを優先して展開する' do\r
+        put :update, {\r
+          :id => @panel.id, \r
+          :panel => Factory.attributes_for(:panel), \r
+          :json => Factory.attributes_for(:panel, :border => 4).to_json\r
+        }\r
+        assigns(:prm)['border'].to_i.should eq @panel.border\r
+      end\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it 'モデルに編集取得依頼する' do\r
+        Panel.stub(:edit).with(any_args).and_return(@panel)\r
+        Panel.should_receive(:edit).exactly(1)\r
+        put :update, :id => @panel.id, :panel => @attr\r
+      end\r
+      it 'コマモデルに上書き補充を依頼している' do\r
+        Panel.any_instance.should_receive(:overwrite).exactly(1)\r
+        put :update, :id => @panel.id, :panel => @attr\r
+      end\r
+      it 'モデルに保存依頼する' do\r
+        Panel.any_instance.should_receive(:store).exactly(1)\r
+        put :update, :id => @panel.id, :panel => @attr\r
+      end\r
+      it "@panelに作成されたコマを保持していて、それがDBにある" do\r
+        put :update, :id => @panel.id, :panel => @attr\r
+        assigns(:panel).should be_a(Panel)\r
+        assigns(:panel).should be_persisted\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          Panel.any_instance.stub(:store).and_return(true)\r
+          put :update, :id => @panel.id, :panel => @attr\r
+          response.status.should eq 302\r
+        end\r
+        it '作成されたコマの表示ページへ遷移する' do\r
+#          Panel.any_instance.stub(:store).and_return(true)\r
+          put :update, :id => @panel.id, :panel => @attr\r
+          response.should redirect_to(Panel.last)\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+#          Panel.any_instance.stub(:store).and_return(true)\r
+          put :update, :id => @panel.id, :panel => @attr, :format => :json\r
+          response.should be_success \r
+        end\r
+      end\r
+    end\r
+    context '作家権限がないとき' do\r
+      before do\r
+        sign_out @user\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          put :update, :id => @panel.id, :panel => @attr\r
+          response.status.should eq 302\r
+        end\r
+        it 'サインインページへ遷移する' do\r
+          put :update, :id => @panel.id, :panel => @attr\r
+          response.body.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード401 Unauthorizedを返す' do\r
+          put :update, :id => @panel.id, :panel => @attr, :format => :json\r
+          response.status.should eq 401\r
+        end\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          put :update, :id => @panel.id, :panel => @attr, :format => :json\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
+    end\r
+    context '検証、保存に失敗した' do\r
+      before do\r
+        Panel.any_instance.stub(:store).and_return(false)\r
+      end\r
+      it "指定のコマを保持している" do\r
+        put :update, :id => @panel.id, :panel => @attr\r
+        assigns(:panel).should eq @panel\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          put :update, :id => @panel.id, :panel => @attr\r
+          response.status.should eq 200\r
+        end\r
+        it '編集ページを描画する' do\r
+          put :update, :id => @panel.id, :panel => @attr\r
+          response.should render_template("edit")\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード422 unprocessable_entity を返す' do\r
+          put :update, :id => @panel.id, :panel => @attr, :format => :json\r
+          response.status.should eq 422\r
+        end\r
+        it '応答メッセージUnprocessable Entityを返す' do\r
+          put :update, :id => @panel.id, :panel => @attr, :format => :json\r
+          response.message.should match(/Unprocessable/)\r
+        end\r
+      end\r
+    end\r
+  end\r
+\r
+  describe '削除に於いて' do\r
+    before do\r
+      @panel = Factory :panel, :author_id => @user.author.id\r
+      Panel.stub(:edit).and_return(@panel)\r
+      sign_in @user\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it 'コマモデルに編集取得を問い合わせている' do\r
+        Panel.should_receive(:edit).exactly(1)\r
+        delete :destroy, :id => @panel.id\r
+      end\r
+      it '@panelにアレを取得している' do\r
+        delete :destroy, :id => @panel.id\r
+        assigns(:panel).id.should eq(@panel.id)\r
+      end\r
+      it 'そのコマを一つのトランザクションで削除する' do\r
+        lambda {\r
+          delete :destroy, :id => @panel.id\r
+        }.should change(Panel, :count)\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          delete :destroy, :id => @panel.id\r
+          response.status.should eq 302\r
+        end\r
+        it 'コマ一覧ページへ遷移する' do\r
+          delete :destroy, :id => @panel.id\r
+          response.should redirect_to(panels_url)\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          delete :destroy, :id => @panel.id, :format => :json\r
+          response.should be_success\r
+        end\r
+      end\r
+    end\r
+    context '作家権限がないとき' do\r
+      before do\r
+        sign_out @user\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          delete :destroy, :id => @panel.id\r
+          response.status.should eq 302\r
+        end\r
+        it 'サインインページへ遷移する' do\r
+          delete :destroy, :id => @panel.id\r
+          response.body.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード401 Unauthorizedを返す' do\r
+          delete :destroy, :id => @panel.id, :format => :json\r
+          response.status.should eq 401\r
+        end\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          delete :destroy, :id => @panel.id, :format => :json\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
+    end\r
+=begin\r
+    context '対象コマがないとき' do\r
+    end\r
+    context '他人のコマだったとき' do\r
+    end\r
+=end\r
+  end\r
+  \r
 end\r
+\r
diff --git a/spec/controllers/stories_controller_spec.rb b/spec/controllers/stories_controller_spec.rb
new file mode 100644 (file)
index 0000000..5124482
--- /dev/null
@@ -0,0 +1,434 @@
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+#ストーリー
+describe StoriesController do
+  before do
+    Factory :admin
+    @license = Factory :license
+    @user = Factory :user_yas
+    @author = @user.author    #ユーザ作成時に連動して作成される
+    @comic = Factory :comic, :author_id => @user.author.id
+    @panel = Factory :panel, :author_id => @author.id
+  end
+  
+
+  describe '閲覧に於いて' do
+    before do
+      @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      Comic.stub(:show).and_return(@comic)
+      sign_in @user
+    end
+    context '事前チェックする' do
+    end
+    context 'つつがなく終わるとき' do
+    end
+    context '作家権限がないとき' do
+    end
+  end
+
+  describe '新規作成フォーム表示に於いて' do
+    before do
+      sign_in @user
+    end
+    context 'つつがなく終わるとき' do
+      it 'ステータスコード200 OKを返す' do
+        get :new
+        response.should be_success 
+      end
+      it '@storyに新規データを用意している' do
+        get :new
+        assigns(:story).should be_a_new(Story)
+      end
+      it 'モデルにデフォルト値補充を依頼している' do
+        Story.any_instance.should_receive(:supply_default).exactly(1)
+        get :new
+      end
+      context 'html形式' do
+        it 'newテンプレートを描画する' do
+          get :new
+          response.should render_template("new")
+        end
+      end
+      context 'js形式' do
+        it 'new.jsテンプレートを描画する' do
+          get :new, :format => :js
+          response.should render_template("new")
+        end
+      end
+    end
+    context '作家権限がないとき' do
+      before do
+        sign_out @user
+      end
+      context 'html形式' do
+        it 'ステータスコード302 Foundを返す' do
+          get :new
+          response.status.should eq 302
+        end
+        it 'サインインページへ遷移する' do
+          get :new
+          response.body.should redirect_to '/users/sign_in'
+        end
+      end
+      context 'js形式' do
+        it 'ステータスコード401 Unauthorizedを返す' do
+          get :new, :format => :js
+          response.status.should eq 401
+        end
+        it '応答メッセージにUnauthorizedを返す' do
+          get :new, :format => :js
+          response.message.should match(/Unauthorized/)
+        end
+      end
+    end
+  end
+  
+  describe '新規作成に於いて' do
+    before do
+      @attr = Factory.attributes_for(:story, :t => nil, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id)
+      sign_in @user
+    end
+    context 'つつがなく終わるとき' do
+      it 'デフォルト値補充を依頼する' do
+        Story.any_instance.should_receive(:supply_default).exactly(1)
+        post :create, :story => @attr
+      end
+      it 'POSTデータから、カラム値を復元している' do
+        Story.any_instance.stub(:store).and_return(true)
+        Story.any_instance.should_receive(:attributes=).exactly(1)
+        post :create, :story => @attr
+      end
+      it '上書き補充を依頼する' do
+        Story.any_instance.should_receive(:overwrite).exactly(1)
+        post :create, :story => @attr
+      end
+      it 'モデルに保存依頼する' do
+        Story.any_instance.should_receive(:store).exactly(1)
+        post :create, :story => @attr
+      end
+      it "@storyに作成されたコマを保持していて、それがDBにある" do
+        post :create, :story => @attr
+        assigns(:story).should be_a(Story)
+        assigns(:story).should be_persisted
+      end
+      context 'html形式' do
+        it 'ステータスコード302 Foundを返す' do
+          Story.any_instance.stub(:store).and_return(true)
+          post :create, :story => @attr
+          response.status.should eq 302
+        end
+        it 'コミックのストーリー表示へ遷移する' do
+#          Story.any_instance.stub(:store).and_return(true)
+          post :create, :story => @attr
+          response.should redirect_to(:action => :show, :id => @attr[:comic_id])
+        end
+      end
+      context 'json形式' do
+        it 'ステータスコード200 OKを返す' do
+#          Story.any_instance.stub(:store).and_return(true)
+          post :create, :story => @attr, :format => :json
+          response.should be_success 
+        end
+        it '作成されたコマをjsonデータで返す' do
+          post :create, :story => @attr, :format => :json
+          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+        end
+        it 'データがアレになっている' do
+          post :create, :story => @attr, :format => :json
+          json = JSON.parse response.body
+          json["t"].should eq 0
+        end
+      end
+    end
+    context '作家権限がないとき' do
+      before do
+        sign_out @user
+      end
+      context 'html形式' do
+        it 'ステータスコード302 Foundを返す' do
+          post :create, :story => @attr
+          response.status.should eq 302
+        end
+        it 'サインインページへ遷移する' do
+          post :create, :story => @attr
+          response.body.should redirect_to '/users/sign_in'
+        end
+      end
+      context 'json形式' do
+        it 'ステータスコード401 Unauthorizedを返す' do
+          post :create, :story => @attr, :format => :json
+          response.status.should eq 401
+        end
+        it '応答メッセージにUnauthorizedを返す' do
+          post :create, :story => @attr, :format => :json
+          response.message.should match(/Unauthorized/)
+        end
+      end
+    end
+    context '検証、保存に失敗した' do
+      before do
+        Story.any_instance.stub(:store).and_return(false)
+      end
+      it "未保存のコマを保持している" do
+        post :create, :story => @attr
+        assigns(:story).should be_a_new(Story)
+      end
+      context 'html形式' do
+        it 'ステータスコード200 OKを返す' do
+          post :create, :story => @attr
+          response.status.should eq 200
+        end
+        it '新規ページを描画する' do
+          post :create, :story => @attr
+          response.should render_template("new")
+        end
+      end
+      context 'json形式' do
+        it 'ステータスコード422 unprocessable_entity を返す' do
+          post :create, :story => @attr, :format => :json
+          response.status.should eq 422
+        end
+        it '応答メッセージUnprocessable Entityを返す' do
+          post :create, :story => @attr, :format => :json
+          response.message.should match(/Unprocessable/)
+        end
+      end
+    end
+  end
+
+  describe '編集フォーム表示に於いて' do
+    before do
+      @story = Factory :story, :author_id => @author.id
+      sign_in @user
+      Story.stub(:show).and_return(@story)
+    end
+    context 'つつがなく終わるとき' do
+      it 'ステータスコード200 OKを返す' do
+        get :edit, :id => @story.id
+        response.should be_success 
+      end
+      it 'コマモデルに単体取得を問い合わせている' do
+        Story.should_receive(:show).exactly(1)
+        get :edit, :id => @story.id
+      end
+      it '@storyにデータを用意している' do
+        get :edit, :id => @story.id
+        assigns(:story).should eq @story
+      end
+      context 'html形式' do
+        it 'editテンプレートを描画する' do
+          get :edit, :id => @story.id
+          response.should render_template("edit")
+        end
+      end
+      context 'js形式' do
+        it 'edit.jsテンプレートを描画する' do
+          get :edit, :id => @story.id, :format => :js
+          response.should render_template("edit")
+        end
+      end
+    end
+    context '作家権限がないとき' do
+      before do
+        sign_out @user
+      end
+      context 'html形式' do
+        it 'ステータスコード302 Foundを返す' do
+          get :edit, :id => @story.id
+          response.status.should eq 302
+        end
+        it 'サインインページへ遷移する' do
+          get :edit, :id => @story.id
+          response.body.should redirect_to '/users/sign_in'
+        end
+      end
+      context 'js形式' do
+        it 'ステータスコード401 Unauthorizedを返す' do
+          get :edit, :id => @story.id, :format => :js
+          response.status.should eq 401
+        end
+        it '応答メッセージにUnauthorizedを返す' do
+          get :edit, :id => @story.id, :format => :js
+          response.message.should match(/Unauthorized/)
+        end
+      end
+    end
+  end
+
+  describe '更新に於いて' do
+    before do
+      @story = Factory :story, :author_id => @user.author.id
+      @attr = Factory.attributes_for(:story, :author_id => @author.id)
+      sign_in @user
+    end
+    context 'つつがなく終わるとき' do
+      it 'モデルに編集取得依頼する' do
+        Story.stub(:edit).with(any_args).and_return(@story)
+        Story.should_receive(:edit).exactly(1)
+        put :update, :id => @story.id, :story => @attr
+      end
+      it 'POSTデータから、カラム値を復元している' do
+        Story.any_instance.stub(:store).and_return(true)
+        Story.any_instance.should_receive(:attributes=).exactly(1)
+        put :update, :id => @story.id, :story => @attr
+      end
+      it '上書き補充を依頼する' do
+        Story.any_instance.should_receive(:overwrite).exactly(1)
+        put :update, :id => @story.id, :story => @attr
+      end
+      it 'モデルに保存依頼する' do
+        Story.any_instance.should_receive(:store).exactly(1)
+        put :update, :id => @story.id, :story => @attr
+      end
+      it "@storyに作成されたストーリーを保持していて、それがDBにある" do
+        put :update, :id => @story.id, :story => @attr
+        assigns(:story).should be_a(Story)
+        assigns(:story).should be_persisted
+      end
+      context 'html形式' do
+        it 'ステータスコード302 Foundを返す' do
+          Story.any_instance.stub(:store).and_return(true)
+          put :update, :id => @story.id, :story => @attr
+          response.status.should eq 302
+        end
+        it 'コミックのストーリー表示へ遷移する' do
+#          Story.any_instance.stub(:store).and_return(true)
+          put :update, :id => @story.id, :story => @attr
+          response.should redirect_to(:action => :show, :id => @attr[:comic_id])
+        end
+      end
+      context 'json形式' do
+        it 'ステータスコード200 OKを返す' do
+#          Story.any_instance.stub(:store).and_return(true)
+          put :update, :id => @story.id, :story => @attr, :format => :json
+          response.should be_success 
+        end
+      end
+    end
+    context '作家権限がないとき' do
+      before do
+        sign_out @user
+      end
+      context 'html形式' do
+        it 'ステータスコード302 Foundを返す' do
+          put :update, :id => @story.id, :story => @attr
+          response.status.should eq 302
+        end
+        it 'サインインページへ遷移する' do
+          put :update, :id => @story.id, :story => @attr
+          response.body.should redirect_to '/users/sign_in'
+        end
+      end
+      context 'json形式' do
+        it 'ステータスコード401 Unauthorizedを返す' do
+          put :update, :id => @story.id, :story => @attr, :format => :json
+          response.status.should eq 401
+        end
+        it '応答メッセージにUnauthorizedを返す' do
+          put :update, :id => @story.id, :story => @attr, :format => :json
+          response.message.should match(/Unauthorized/)
+        end
+      end
+    end
+    context '検証、保存に失敗した' do
+      before do
+        Story.any_instance.stub(:store).and_return(false)
+      end
+      it "指定のコマを保持している" do
+        put :update, :id => @story.id, :story => @attr
+        assigns(:story).should eq @story
+      end
+      context 'html形式' do
+        it 'ステータスコード200 OKを返す' do
+          put :update, :id => @story.id, :story => @attr
+          response.status.should eq 200
+        end
+        it '編集ページを描画する' do
+          put :update, :id => @story.id, :story => @attr
+          response.should render_template("edit")
+        end
+      end
+      context 'json形式' do
+        it 'ステータスコード422 unprocessable_entity を返す' do
+          put :update, :id => @story.id, :story => @attr, :format => :json
+          response.status.should eq 422
+        end
+        it '応答メッセージUnprocessable Entityを返す' do
+          put :update, :id => @story.id, :story => @attr, :format => :json
+          response.message.should match(/Unprocessable/)
+        end
+      end
+    end
+  end
+
+  describe '削除に於いて' do\r
+    before do\r
+      @story = Factory :story, :author_id => @author.id
+      sign_in @user
+      Story.stub(:edit).and_return(@story)\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it 'ストーリーモデルに編集取得を問い合わせている' do\r
+        Story.should_receive(:edit).exactly(1)\r
+        delete :destroy, :id => @story.id\r
+      end\r
+      it '@storyにアレを取得している' do\r
+        delete :destroy, :id => @story.id\r
+        assigns(:story).id.should eq(@story.id)\r
+      end\r
+      it 'そのストーリーを一つのトランザクションで削除する' do\r
+        lambda {\r
+          delete :destroy, :id => @story.id\r
+        }.should change(Story, :count)\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          delete :destroy, :id => @story.id\r
+          response.status.should eq 302\r
+        end\r
+        it 'ストーリー一覧ページへ遷移する' do\r
+          delete :destroy, :id => @story.id\r
+          response.should redirect_to(story_path(@story.comic_id))\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          delete :destroy, :id => @story.id, :format => :json\r
+          response.should be_success\r
+        end\r
+      end\r
+    end\r
+    context '作家権限がないとき' do\r
+      before do\r
+        sign_out @user\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          delete :destroy, :id => @story.id\r
+          response.status.should eq 302\r
+        end\r
+        it 'サインインページへ遷移する' do\r
+          delete :destroy, :id => @story.id\r
+          response.body.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード401 Unauthorizedを返す' do\r
+          delete :destroy, :id => @story.id, :format => :json\r
+          response.status.should eq 401\r
+        end\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          delete :destroy, :id => @story.id, :format => :json\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
+    end\r
+=begin\r
+    context '対象ストーリーがないとき' do\r
+    end\r
+    context '他人のストーリーだったとき' do\r
+    end\r
+=end\r
+  end\r
+  \r
+end
index 2f449d2..2941e5f 100644 (file)
@@ -82,39 +82,6 @@ Factory.define :comic, :class => Comic do |comic|
   comic.width 100
   comic.height 10
   comic.visible 3
-  comic.editable 3
-end
-
-Factory.define :normal_comic, :class => Comic do |comic|
-  comic.title "normal_comic"
-  comic.width 100
-  comic.height 10
-  comic.visible 3
-  comic.editable 0
-end
-
-Factory.define :visible_comic, :class => Comic do |comic|
-  comic.title "visible_comic"
-  comic.width 100
-  comic.height 10
-  comic.visible 3
-  comic.editable 0
-end
-
-Factory.define :editable_comic, :class => Comic do |comic|
-  comic.title "editable_comic"
-  comic.width 100
-  comic.height 10
-  comic.visible 3
-  comic.editable 3
-end
-
-Factory.define :hidden_comic, :class => Comic do |comic|
-  comic.title "hidden_comic"
-  comic.width 100
-  comic.height 10
-  comic.visible 0
-  comic.editable 0
 end
 
 Factory.define :original_picture, :class => OriginalPicture do |op|
@@ -195,14 +162,19 @@ Factory.define :panel_picture, :class => PanelPicture do |pp|
 end
 
 Factory.define :panel, :class => Panel do |panel|
-  panel.comic_id 1
   panel.border 1
   panel.x nil
   panel.y nil
   panel.z nil
-  panel.t 0
   panel.width 100
   panel.height 300
+  panel.publish 1
   panel.author_id 1
 end
 
+Factory.define :story, :class => Story do |story|
+  story.comic_id 1
+  story.panel_id 1
+  story.author_id 1
+  story.t 0
+end
index 42bb737..3abe223 100644 (file)
@@ -94,16 +94,16 @@ describe Artist do
       c.should eq [@artist]
     end
     it '時系列で並んでいる' do
-      n = Factory :artist, :author_id => @author.id, :name => 'artist'
+      n = Factory :artist, :author_id => @author.id, :name => 'artist', :updated_at => Time.now + 100
       l = Artist.list
       l.should eq [n, @artist]
     end
     context 'DBに5件あって1ページの件数を2件に変えたとして' do
       before do
-        @artist2 = Factory :artist, :author_id => @author.id, :name => 'artist2'
-        @artist3 = Factory :artist, :author_id => @author.id, :name => 'artist3'
-        @artist4 = Factory :artist, :author_id => @author.id, :name => 'artist4'
-        @artist5 = Factory :artist, :author_id => @author.id, :name => 'artist5'
+        @artist2 = Factory :artist, :author_id => @author.id, :name => 'artist2', :updated_at => Time.now + 100
+        @artist3 = Factory :artist, :author_id => @author.id, :name => 'artist3', :updated_at => Time.now + 200
+        @artist4 = Factory :artist, :author_id => @author.id, :name => 'artist4', :updated_at => Time.now + 300
+        @artist5 = Factory :artist, :author_id => @author.id, :name => 'artist5', :updated_at => Time.now + 400
         Artist.stub(:default_page_size).and_return(2)
       end
       it '通常は2件を返す' do
index 599f943..b9abac2 100644 (file)
@@ -4,6 +4,7 @@ require 'spec_helper'
 describe Comic do
   before do
     Factory :admin
+    @license = Factory :license
     @user = Factory( :user_yas)
     @author = @user.author
     @artist = Factory :artist_yas, :author_id => @author.id
@@ -14,81 +15,67 @@ describe Comic do
     end
     
     it 'オーソドックスなデータなら通る' do
-      @comic = Factory.build :normal_comic, :author_id => @author.id
+      @comic = Factory.build :comic, :author_id => @author.id
       @comic.should be_valid
     end
     
     context 'titleを検証するとき' do
       it 'nullなら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :title => nil
+        @comic = Factory.build :comic, :author_id => @author.id, :title => nil
         @comic.should_not be_valid
       end
       it '100文字以上なら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :title => 'a'*101
+        @comic = Factory.build :comic, :author_id => @author.id, :title => 'a'*101
         @comic.should_not be_valid
       end
     end
     context 'widthを検証するとき' do
       it 'nullなら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :width => nil
+        @comic = Factory.build :comic, :author_id => @author.id, :width => nil
         @comic.should_not be_valid
       end
       it '0なら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :width => 0
+        @comic = Factory.build :comic, :author_id => @author.id, :width => 0
         @comic.should_not be_valid
       end
       it '負でも失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :width => -1
+        @comic = Factory.build :comic, :author_id => @author.id, :width => -1
         @comic.should_not be_valid
       end
       it '正なら通る' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :width => 1
+        @comic = Factory.build :comic, :author_id => @author.id, :width => 1
         @comic.should be_valid
       end
     end
     context 'heightを検証するとき' do
       it 'nullなら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :height => nil
+        @comic = Factory.build :comic, :author_id => @author.id, :height => nil
         @comic.should_not be_valid
       end
       it '0なら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :height => 0
+        @comic = Factory.build :comic, :author_id => @author.id, :height => 0
         @comic.should_not be_valid
       end
       it '負でも失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :height => -1
+        @comic = Factory.build :comic, :author_id => @author.id, :height => -1
         @comic.should_not be_valid
       end
       it '正なら通る' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :height => 1
+        @comic = Factory.build :comic, :author_id => @author.id, :height => 1
         @comic.should be_valid
       end
     end
     context 'visibleを検証するとき' do
       it 'nullなら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :visible => nil
+        @comic = Factory.build :comic, :author_id => @author.id, :visible => nil
         @comic.should_not be_valid
       end
       it '負なら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :visible => -1
+        @comic = Factory.build :comic, :author_id => @author.id, :visible => -1
         @comic.should_not be_valid
       end
       it '4以上なら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :visible => 4
-        @comic.should_not be_valid
-      end
-    end
-    context 'editableを検証するとき' do
-      it 'nullなら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :editable => nil
-        @comic.should_not be_valid
-      end
-      it '負なら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :visible => -1
-        @comic.should_not be_valid
-      end
-      it '4以上なら失敗する' do
-        @comic = Factory.build :normal_comic, :author_id => @author.id, :visible => 4
+        @comic = Factory.build :comic, :author_id => @author.id, :visible => 4
         @comic.should_not be_valid
       end
     end
@@ -102,13 +89,8 @@ describe Comic do
     context '初期値を補充するとき' do
       it '空なら0が補充される' do
         @comic.supply_default
-        @comic.editable.should == 0
         @comic.visible.should == 0
       end
-      it 'editableが空でないなら変化なし' do
-        @comic.editable = 1
-        lambda{@comic.supply_default}.should_not change(@comic, :editable)
-      end
       it 'visibleが空でないなら変化なし' do
         @comic.visible = 1
         lambda{@comic.supply_default}.should_not change(@comic, :visible)
@@ -120,15 +102,15 @@ describe Comic do
     before do
     end
     it '自作のコミックならyes' do
-      comic = Factory :normal_comic, :author_id => @author.id
+      comic = Factory :comic, :author_id => @author.id
       comic.own?(@author).should == true
     end
     it '他人のコミックならno' do
-      comic = Factory :normal_comic, :author_id => @author.id - 1
+      comic = Factory :comic, :author_id => 0
       comic.own?(@author).should == false
     end
     it '作家が不明ならno' do
-      comic = Factory :normal_comic, :author_id => @author.id
+      comic = Factory :comic, :author_id => @author.id
       comic.own?(nil).should == false
     end
   end
@@ -137,49 +119,79 @@ describe Comic do
     end
     it '自作の公開コミックを見るときは許可する' do
       Comic.any_instance.stub(:own?).and_return(true)
-      comic = Factory :normal_comic, :author_id => @author.id
+      comic = Factory :comic, :author_id => @author.id, :visible => 3
       comic.visible?(@author).should == true
     end
     it '自作のコミックは非公開でも許可する' do
       Comic.any_instance.stub(:own?).and_return(true)
-      comic = Factory :hidden_comic, :author_id => @author.id
+      comic = Factory :comic, :author_id => @author.id, :visible => 0
       comic.visible?(@author).should == true
     end
     it '他人のコミックでも公開コミックなら許可する' do
       Comic.any_instance.stub(:own?).and_return(false)
-      comic = Factory :normal_comic, :author_id => @author.id - 1
+      comic = Factory :comic, :author_id => 0, :visible => 3
       comic.visible?(@author).should == true
     end
     it '他人のコミックで非公開コミックなら許可しない' do
       Comic.any_instance.stub(:own?).and_return(false)
-      comic = Factory :hidden_comic, :author_id => @author.id - 1
+      comic = Factory :comic, :author_id => 0, :visible => 0
       comic.visible?(@author).should == false
     end
   end
   describe '単体取得に於いて' do
     before do
-      @comic = Factory :normal_comic, :author_id => @author.id
+      @comic = Factory :comic, :author_id => @author.id
     end
     it '指定のコミックを返す' do
       c = Comic.show @comic.id, @author.id
       c.should eq @comic
     end
-    context '関連テーブルオプションがないとき' do
-      it '作家データだけを含んでいる' do
+  end
+  describe '関連テーブルプションに於いて' do
+    context 'オプションがないとき' do
+      it '2つの項目を含んでいる' do
         r = Comic.show_include_opt
-        r.should eq [:author]
+        r.should have(2).items
       end
-    end
-    context '関連テーブルオプションでコマを含ませたとき' do
-      it '作家データとコマデータを含んでいる' do
-        r = Comic.show_include_opt(:include => :panels)
-        r.should eq [:author, :panels]
+      it '作家を含んでいる' do
+        r = Comic.show_include_opt
+        r.has_key?(:author).should be_true
+      end
+      it 'ストーリーを含んでいる' do
+        r = Comic.show_include_opt
+        r.has_key?(:stories).should be_true
       end
+        it 'ストーリーはコマを含んでいる' do
+          r = Comic.show_include_opt
+          r[:stories].has_key?(:panel).should be_true
+        end
+    end
+  end
+  describe 'json単体出力オプションに於いて' do
+    it 'includeキーを含んでいる' do
+      r = Comic.show_json_include_opt
+      r.has_key?(:include).should be_true
+    end
+    it '2つの項目を含んでいる' do
+      r = Comic.show_json_include_opt[:include]
+      r.should have(2).items
+    end
+    it '作家を含んでいる' do
+      r = Comic.show_json_include_opt[:include]
+      r.has_key?(:author).should be_true
     end
+    it 'ストーリーを含んでいる' do
+      r = Comic.show_json_include_opt[:include]
+      r.has_key?(:stories).should be_true
+    end
+      it 'ストーリーはコマを含んでいる' do
+        r = Comic.show_json_include_opt[:include]
+        r[:stories].has_key?(:panel).should be_true
+      end
   end
   describe '一覧取得に於いて' do
     before do
-      @comic = Factory :normal_comic, :author_id => @author.id
+      @comic = Factory :comic, :author_id => @author.id
     end
     context 'page補正について' do
       it '文字列から数値に変換される' do
@@ -211,21 +223,21 @@ describe Comic do
       c.should eq [@comic]
     end
     it '非公開コミックは(自分のコミックであっても)含んでいない' do
-      Factory :hidden_comic, :author_id => @author.id
+      Factory :comic, :author_id => @author.id, :visible => 0
       c = Comic.list
       c.should eq [@comic]
     end
     it '時系列で並んでいる' do
-      v = Factory :visible_comic, :author_id => @author.id
+      v = Factory :comic, :author_id => @author.id, :updated_at => Time.now + 100
       c = Comic.list
       c.should eq [v, @comic]
     end
     context 'DBに5件あって1ページの件数を2件に変えたとして' do
       before do
-        @comic2 = Factory :visible_comic, :author_id => @author.id
-        @comic3 = Factory :editable_comic, :author_id => @author.id
-        @comic4 = Factory :normal_comic, :author_id => @author.id
-        @comic5 = Factory :editable_comic, :author_id => @author.id
+        @comic2 = Factory :comic, :author_id => @author.id, :updated_at => Time.now + 100
+        @comic3 = Factory :comic, :author_id => @author.id, :updated_at => Time.now + 200
+        @comic4 = Factory :comic, :author_id => @author.id, :updated_at => Time.now + 300
+        @comic5 = Factory :comic, :author_id => @author.id, :updated_at => Time.now + 400
         Comic.stub(:default_page_size).and_return(2)
       end
       it '通常は2件を返す' do
@@ -247,4 +259,48 @@ describe Comic do
       end
     end
   end
+  describe 'list関連テーブルプションに於いて' do
+    it 'includeキーを含んでいる' do
+      r = Comic.list_opt
+      r.has_key?(:include).should be_true
+    end
+    it '2つの項目を含んでいる' do
+      r = Comic.list_opt[:include]
+      r.should have(2).items
+    end
+    it 'ストーリーを含んでいる' do
+      r = Comic.list_opt[:include]
+      r.has_key?(:stories).should be_true
+    end
+      it 'ストーリーはコマを含んでいる' do
+        r = Comic.list_opt[:include]
+        r[:stories].has_key?(:panel).should be_true
+      end
+    it '作家を含んでいる' do
+      r = Comic.list_opt[:include]
+      r.has_key?(:author).should be_true
+    end
+  end
+  describe 'json一覧出力オプションに於いて' do
+    it 'includeキーを含んでいる' do
+      r = Comic.list_json_opt
+      r.has_key?(:include).should be_true
+    end
+    it '2つの項目を含んでいる' do
+      r = Comic.list_json_opt[:include]
+      r.should have(2).items
+    end
+    it 'ストーリーを含んでいる' do
+      r = Comic.list_json_opt[:include]
+      r.has_key?(:stories).should be_true
+    end
+      it 'ストーリーはコマを含んでいる' do
+        r = Comic.list_json_opt[:include]
+        r[:stories].has_key?(:panel).should be_true
+      end
+    it '作家を含んでいる' do
+      r = Comic.list_json_opt[:include]
+      r.has_key?(:author).should be_true
+    end
+  end
 end
index f61ef84..dd685ea 100644 (file)
@@ -224,6 +224,41 @@ describe OriginalPicture do
       end
     end
   end
+  describe '編集取得に於いて' do
+    before do
+      @op = Factory :original_picture, :artist_id => @artist.id
+    end
+    it '指定の原画を返す' do
+      pic = OriginalPicture.edit @op.id, @artist
+      pic.should eq @op
+    end
+    context '関連テーブルオプションがないとき' do
+      it 'ライセンスと素材を含んでいる' do
+        r = OriginalPicture.show_include_opt
+        r.should eq [:license, :resource_picture]
+      end
+    end
+    context '関連テーブルオプションで絵師を含ませたとき' do
+      it 'ライセンスと素材と作者データを含んでいる' do
+        r = OriginalPicture.show_include_opt(:include => :artist)
+        r.should eq [:license, :resource_picture, :artist]
+      end
+    end
+    context '他人の原画を開こうとしたとき' do
+      it '403Forbidden例外を返す' do
+        lambda{
+          pic = OriginalPicture.edit @op.id, @other_artist
+        }.should raise_error(ActiveRecord::Forbidden)
+      end
+    end
+    context '存在しない原画を開こうとしたとき' do
+      it '404RecordNotFound例外を返す' do
+        lambda{
+          pic = OriginalPicture.edit 0, @artist
+        }.should raise_error(ActiveRecord::RecordNotFound)
+      end
+    end
+  end
   describe 'json単体出力オプションに於いて' do
     it 'includeキーがライセンスと素材を含んでいる' do
       r = OriginalPicture.show_json_include_opt
@@ -269,16 +304,16 @@ describe OriginalPicture do
       pic.should eq [@op]
     end
     it '時系列で並んでいる' do
-      newpic = Factory :original_picture, :artist_id => @artist.id
+      newpic = Factory :original_picture, :artist_id => @artist.id, :updated_at => Time.now + 100
       pic = OriginalPicture.list @artist.id
       pic.should eq [newpic, @op]
     end
     context 'DBに5件あって1ページの件数を2件に変えたとして' do
       before do
-        @op2 = Factory :original_picture, :artist_id => @artist.id
-        @op3 = Factory :original_picture, :artist_id => @artist.id
-        @op4 = Factory :original_picture, :artist_id => @artist.id
-        @op5 = Factory :original_picture, :artist_id => @artist.id
+        @op2 = Factory :original_picture, :artist_id => @artist.id, :updated_at => Time.now + 100
+        @op3 = Factory :original_picture, :artist_id => @artist.id, :updated_at => Time.now + 200
+        @op4 = Factory :original_picture, :artist_id => @artist.id, :updated_at => Time.now + 300
+        @op5 = Factory :original_picture, :artist_id => @artist.id, :updated_at => Time.now + 400
         OriginalPicture.stub(:default_page_size).and_return(2)
       end
       it '通常は2件を返す' do
index 4deb967..1520382 100644 (file)
@@ -1,9 +1,223 @@
 # -*- encoding: utf-8 -*-
 require 'spec_helper'
-
+#コマ絵
 describe PanelPicture do
+  before do
+    Factory :admin
+    @user = Factory( :user_yas)
+    @author = @user.author
+    @artist = Factory :artist_yas, :author_id => @author.id
+    @license = Factory :license
+    @op = Factory :original_picture, :artist_id => @artist.id, :license_id => @license.id
+    @rp = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id
+    @panel = Factory :panel, :author_id => @author.id
+  end
+  
   describe '検証に於いて' do
     before do
     end
+    it 'オーソドックスなデータなら通る' do
+      @pp = Factory.build :panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id
+      @pp.save!
+      @pp.should be_valid
+    end
+    
+    context 'panel_idを検証するとき' do
+      before do
+        @pp = Factory.build :panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id
+      end
+      it 'テストデータの確認' do
+        @pp.panel_id = @panel.id
+        @pp.should be_valid
+      end
+      it '数値でなければ失敗する' do
+        @pp.panel_id = 'a'
+        @pp.should_not be_valid
+      end
+    end
+    context 'resource_picture_idを検証するとき' do
+      before do
+        @pp = Factory.build :panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id
+      end
+      it 'テストデータの確認' do
+        @pp.resource_picture_id = @rp.id
+        @pp.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @pp.resource_picture_id = nil
+        @pp.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @pp.resource_picture_id = 'a'
+        @pp.should_not be_valid
+      end
+      it '存在するフキダシテンプレートでなければ失敗する' do
+        @pp.resource_picture_id = 0
+        @pp.should_not be_valid
+      end
+    end
+    context 'linkを検証するとき' do
+      before do
+        @pp = Factory.build :panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id
+      end
+      it 'テストデータの確認' do
+        @pp.link = 'abcdefghi0abcdefghi0abcdefghi0abcdefghi0abcdefghi0'*4
+        @pp.should be_valid
+      end
+      it 'nullでも通る' do
+        @pp.link = ''
+        @pp.should be_valid
+      end
+      it '201文字以上なら失敗する' do
+        @pp.link = 'a'*201
+        @pp.should_not be_valid
+      end
+    end
+    context 'xを検証するとき' do
+      before do
+        @pp = Factory.build :panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id
+      end
+      it 'テストデータの確認' do
+        @pp.x = '1'
+        @pp.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @pp.x = nil
+        @pp.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @pp.x = 'a'
+        @pp.should_not be_valid
+      end
+      it '0なら通る' do
+        @pp.x = '0'
+        @pp.should be_valid
+      end
+      it '負でも通る' do
+        @pp.x = -1
+        @pp.should be_valid
+      end
+    end
+    context 'yを検証するとき' do
+      before do
+        @pp = Factory.build :panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id
+      end
+      it 'テストデータの確認' do
+        @pp.y = '1'
+        @pp.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @pp.y = nil
+        @pp.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @pp.y = 'a'
+        @pp.should_not be_valid
+      end
+      it '0なら通る' do
+        @pp.y = '0'
+        @pp.should be_valid
+      end
+      it '負でも通る' do
+        @pp.y = -1
+        @pp.should be_valid
+      end
+    end
+    context 'widthを検証するとき' do
+      before do
+        @pp = Factory.build :panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id
+      end
+      it 'テストデータの確認' do
+        @pp.width = 1
+        @pp.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @pp.width = nil
+        @pp.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @pp.width = 'a'
+        @pp.should_not be_valid
+      end
+      it '0なら失敗する' do
+        @pp.width = '0'
+        @pp.should_not be_valid
+      end
+      it '負でも通る' do
+        @pp.width = -1
+        @pp.should be_valid
+      end
+    end
+    context 'heightを検証するとき' do
+      before do
+        @pp = Factory.build :panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id
+      end
+      it 'テストデータの確認' do
+        @pp.height = '1'
+        @pp.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @pp.height = nil
+        @pp.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @pp.height = 'a'
+        @pp.should_not be_valid
+      end
+      it '0なら失敗する' do
+        @pp.height = '0'
+        @pp.should_not be_valid
+      end
+      it '負でも通る' do
+        @pp.height = -1
+        @pp.should be_valid
+      end
+    end
+    context 'zを検証するとき' do
+      before do
+        @pp = Factory.build :panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id
+      end
+      it 'テストデータの確認' do
+        @pp.z = 1
+        @pp.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @pp.z = nil
+        @pp.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @pp.z = 'a'
+        @pp.should_not be_valid
+      end
+      it '負なら失敗する' do
+        @pp.z = -1
+        @pp.should_not be_valid
+      end
+      it '負なら失敗する' do
+        @pp.z = 0
+        @pp.should_not be_valid
+      end
+    end
+    context 'tを検証するとき' do
+      before do
+        @pp = Factory.build :panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id
+      end
+      it 'テストデータの確認' do
+        @pp.t = 0
+        @pp.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @pp.t = nil
+        @pp.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @pp.t = 'a'
+        @pp.should_not be_valid
+      end
+      it '負なら失敗する' do
+        @pp.t = -1
+        @pp.should_not be_valid
+      end
+    end
   end
 end
index 0ec0e91..1398367 100644 (file)
@@ -10,7 +10,6 @@ describe Panel do
     @artist = Factory :artist_yas, :author_id => @author.id\r
     @other_user = Factory( :user_yas)\r
     @other_author = @other_user.author\r
-    @other_artist = Factory :artist_yas, :author_id => @other_author.id\r
     @op = Factory :original_picture, :artist_id => @artist.id, :license_id => @license.id\r
     @rp = Factory :resource_picture, :original_picture_id => @op.id, :license_id => @license.id\r
     @sbt = Factory :speech_balloon_template\r
@@ -18,26 +17,16 @@ describe Panel do
   \r
   describe '検証に於いて' do\r
     before do\r
-      @comic = Factory :comic, :author_id => @author.id\r
     end\r
     \r
     it 'オーソドックスなデータなら通る' do\r
-      @panel = Factory.build :panel, :author_id => @author.id, :comic_id => @comic.id\r
+      @panel = Factory.build :panel, :author_id => @author.id\r
       @panel.should be_valid\r
     end\r
     \r
-    context 'comic_idを検証するとき' do\r
-      before do\r
-        @panel = Factory.build :panel, :author_id => @author.id, :comic_id => nil\r
-      end\r
-      it 'テストデータの確認' do\r
-        @panel.comic_id = @comic.id\r
-        @panel.should be_valid\r
-      end\r
-    end\r
     context 'widthを検証するとき' do\r
       before do\r
-        @panel = Factory.build :panel, :author_id => @author.id, :comic_id => @comic.id\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
       end\r
       it 'テストデータの確認' do\r
         @panel.width = 1\r
@@ -62,7 +51,7 @@ describe Panel do
     end\r
     context 'heightを検証するとき' do\r
       before do\r
-        @panel = Factory.build :panel, :author_id => @author.id, :comic_id => @comic.id\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
       end\r
       it 'テストデータの確認' do\r
         @panel.height = '1'\r
@@ -87,7 +76,7 @@ describe Panel do
     end\r
     context 'borderを検証するとき' do\r
       before do\r
-        @panel = Factory.build :panel, :author_id => @author.id, :comic_id => @comic.id\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
       end\r
       it 'テストデータの確認' do\r
         @panel.border = '1'\r
@@ -112,7 +101,7 @@ describe Panel do
     end\r
     context 'xを検証するとき' do\r
       before do\r
-        @panel = Factory.build :panel, :author_id => @author.id, :comic_id => @comic.id\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
       end\r
       it 'テストデータの確認' do\r
         @panel.x = '1'\r
@@ -133,7 +122,7 @@ describe Panel do
     end\r
     context 'yを検証するとき' do\r
       before do\r
-        @panel = Factory.build :panel, :author_id => @author.id, :comic_id => @comic.id\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
       end\r
       it 'テストデータの確認' do\r
         @panel.y = '1'\r
@@ -154,7 +143,7 @@ describe Panel do
     end\r
     context 'zを検証するとき' do\r
       before do\r
-        @panel = Factory.build :panel, :author_id => @author.id, :comic_id => @comic.id\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
       end\r
       it 'テストデータの確認' do\r
         @panel.z = '1'\r
@@ -173,30 +162,9 @@ describe Panel do
         @panel.should_not be_valid\r
       end\r
     end\r
-    context 'tを検証するとき' do\r
-      before do\r
-        @panel = Factory.build :panel, :author_id => @author.id, :comic_id => @comic.id\r
-      end\r
-      it 'テストデータの確認' do\r
-        @panel.t = '1'\r
-        @panel.should be_valid\r
-      end\r
-      it '数値でなければ失敗する' do\r
-        @panel.t = 'a'\r
-        @panel.should_not be_valid\r
-      end\r
-      it '0なら通る' do\r
-        @panel.t = '0'\r
-        @panel.should be_valid\r
-      end\r
-      it '負でも失敗する' do\r
-        @panel.t = -1\r
-        @panel.should_not be_valid\r
-      end\r
-    end\r
     context 'author_idを検証するとき' do\r
       before do\r
-        @panel = Factory.build :panel, :author_id => @author.id, :comic_id => @comic.id\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
       end\r
       it 'テストデータの確認' do\r
         @panel.author_id = @author.id\r
@@ -217,97 +185,30 @@ describe Panel do
     end\r
     context '全体を検証するとき' do\r
       before do\r
-        @panel = Factory :panel, :author_id => @author.id, :comic_id => @comic.id\r
+        @panel = Factory :panel, :author_id => @author.id\r
       end\r
     end\r
   end\r
   \r
-  describe 'ã\83\87ã\83¼ã\82¿補充に於いて' do\r
+  describe 'ã\83\87ã\83\95ã\82©ã\83«ã\83\88å\80¤補充に於いて' do\r
     before do\r
-      @comic = Factory :comic, :author_id => @author.id\r
-      @panel = Factory.build :panel, :comic_id => @comic.id\r
-    end\r
-    context 'widthを補充' do\r
-      it '空の時はコミックから補充する' do\r
-        @panel.width = nil\r
-        @panel.supply_default @author\r
-        @panel.width.should eq @comic.width\r
-      end\r
-      it '空の時でもコミックが不在なら補充しない' do\r
-        @panel.width = nil\r
-        @panel.comic_id = nil\r
-        @panel.supply_default @author\r
-        @panel.width.should be_nil\r
-      end\r
-      it '空でない時は変化しない' do\r
-        @panel.width = 45\r
-        lambda {\r
-          @panel.supply_default @author\r
-        }.should_not change @panel, :width\r
-      end\r
-    end\r
-    context 'heightを補充' do\r
-      it '空の時はコミックから補充する' do\r
-        @panel.height = nil\r
-        @panel.supply_default @author\r
-        @panel.height.should eq @comic.height\r
-      end\r
-      it '空の時でもコミックが不在なら補充しない' do\r
-        @panel.height = nil\r
-        @panel.comic_id = nil\r
-        @panel.supply_default @author\r
-        @panel.height.should be_nil\r
-      end\r
-      it '空でない時は変化しない' do\r
-        @panel.height = 87\r
-        lambda {\r
-          @panel.supply_default @author\r
-        }.should_not change @panel, :height\r
-      end\r
+      @panel = Factory.build :panel, :author_id => @author.id\r
     end\r
-    context 'borderを補充' do\r
-      it '空の時は0を補充する' do\r
-        @panel.border = nil\r
-        @panel.supply_default @author\r
-        @panel.border.should eq 0\r
-      end\r
-      it '空でない時は変化しない' do\r
-        @panel.border = 1\r
-        lambda {\r
-          @panel.supply_default @author\r
-        }.should_not change @panel, :border\r
-      end\r
+    it 'borderは2を補充する' do\r
+      @panel.border = nil\r
+      @panel.supply_default\r
+      @panel.border.should eq 2\r
     end\r
-    context 'tを補充' do\r
-      it '空の時はコミック内のtの最大値+1を補充する' do\r
-        pl = Factory :panel, :author_id => @author.id, :comic_id => @comic.id, :t => 0\r
-        @panel.t = nil\r
-        @panel.supply_default @author\r
-        @panel.t.should eq 1\r
-      end\r
-      it '空でコミック初のコマなら0を補充する' do\r
-        @panel.t = nil\r
-        @panel.supply_default @author\r
-        @panel.t.should eq 0\r
-      end\r
-      it '空の時でも更新ケースなら補充しない' do\r
-        pl = Factory :panel, :author_id => @author.id, :comic_id => @comic.id, :t => 1\r
-        pl.t = nil\r
-        lambda {\r
-          pl.supply_default @author\r
-        }.should_not change pl, :t\r
-      end\r
-      it '空でない時は変化しない' do\r
-        @panel.t = 1\r
-        lambda {\r
-          @panel.supply_default @author\r
-        }.should_not change @panel, :t\r
-      end\r
+  end\r
+  \r
+  describe '上書き補充に於いて' do\r
+    before do\r
+      @panel = Factory.build :panel, :author_id => @author.id\r
     end\r
     context 'author_idを補充' do\r
       it 'ログイン中の作家idを補充する' do\r
         @panel.author_id = nil\r
-        @panel.supply_default @author\r
+        @panel.overwrite @author\r
         @panel.author_id.should eq @author.id\r
       end\r
     end\r
@@ -316,53 +217,54 @@ describe Panel do
   \r
   describe '作者判定に於いて' do\r
     before do\r
-      @comic = Factory :comic, :author_id => @author.id\r
     end\r
     it '自作のコマならyes' do\r
-      panel = Factory :panel, :author_id => @author.id, :comic_id => @comic.id\r
+      panel = Factory :panel, :author_id => @author.id\r
       panel.own?(@author).should == true\r
     end\r
     it '他人のコマならno' do\r
-      panel = Factory :panel, :author_id => @other_author.id, :comic_id => @comic.id\r
-      panel.own?(@author).should == false\r
+      panel = Factory :panel, :author_id => @author.id\r
+      panel.own?(@other_author).should == false\r
     end\r
     it '作家が不明ならno' do\r
-      panel = Factory :panel, :author_id => @author.id, :comic_id => @comic.id\r
+      panel = Factory :panel, :author_id => @author.id\r
       panel.own?(nil).should == false\r
     end\r
   end\r
   describe '閲覧許可に於いて' do\r
     before do\r
-      @comic = Factory :comic, :author_id => @author.id\r
     end\r
-    it '自作の公開コミックのコマを見るときは許可する' do\r
-      Comic.any_instance.stub(:visible?).and_return(true)\r
-      panel = Factory :panel, :author_id => @author.id, :comic_id => @comic.id\r
+    it '自作のコマを見るときは許可する' do\r
+      Panel.any_instance.stub(:own?).and_return(true)\r
+      Panel.any_instance.stub(:publish?).and_return(true)\r
+      panel = Factory :panel, :author_id => @author.id\r
       panel.visible?(@author).should == true\r
     end\r
-    it '自作のコマは非公開コミックでも許可する' do\r
-      Comic.any_instance.stub(:visible?).and_return(false)\r
-      panel = Factory :panel, :author_id => @author.id, :comic_id => @comic.id\r
+    it '自作のコマは非公開でも許可する' do\r
+      Panel.any_instance.stub(:own?).and_return(true)\r
+      Panel.any_instance.stub(:publish?).and_return(false)\r
+      panel = Factory :panel, :author_id => @author.id\r
       panel.visible?(@author).should == true\r
     end\r
-    it '他人のコマでも公開コミックなら許可する' do\r
-      Comic.any_instance.stub(:visible?).and_return(true)\r
-      panel = Factory :panel, :author_id => @other_author.id, :comic_id => @comic.id\r
+    it '他人のコマでも公開なら許可する' do\r
+      Panel.any_instance.stub(:own?).and_return(false)\r
+      Panel.any_instance.stub(:publish?).and_return(true)\r
+      panel = Factory :panel, :author_id => @author.id\r
       panel.visible?(@author).should == true\r
     end\r
-    it '他人のコマで非公開コミックなら許可しない' do\r
-      Comic.any_instance.stub(:visible?).and_return(false)\r
-      panel = Factory :panel, :author_id => @other_author.id, :comic_id => @comic.id\r
+    it '他人のコマで非公開なら許可しない' do\r
+      Panel.any_instance.stub(:own?).and_return(false)\r
+      Panel.any_instance.stub(:publish?).and_return(false)\r
+      panel = Factory :panel, :author_id => @author.id\r
       panel.visible?(@author).should == false\r
     end\r
   end\r
   describe '単体取得に於いて' do\r
     before do\r
-      @comic = Factory :comic, :author_id => @author.id\r
-      @panel = Factory :panel, :comic_id => @comic.id, :author_id => @author.id\r
+      @panel = Factory :panel, :author_id => @author.id\r
     end\r
     it '指定のコマを返す' do\r
-      Comic.any_instance.stub(:visible?).and_return(true)\r
+      Panel.any_instance.stub(:visible?).and_return(true)\r
       pl = Panel.show @panel.id, @author\r
       pl.should eq @panel\r
     end\r
@@ -382,15 +284,36 @@ describe Panel do
       end\r
     end\r
   end\r
+  describe '単体取得に於いて' do\r
+    before do\r
+      @panel = Factory :panel, :author_id => @author.id\r
+    end\r
+    it '指定のコマを返す' do\r
+      Panel.any_instance.stub(:own?).and_return(true)\r
+      pl = Panel.edit @panel.id, @author\r
+      pl.should eq @panel\r
+    end\r
+    context '他人のコマを開こうとしたとき' do\r
+      it '403Forbidden例外を返す' do\r
+        Panel.any_instance.stub(:own?).and_return(false)\r
+        lambda{\r
+          Panel.edit @panel.id, @author\r
+        }.should raise_error(ActiveRecord::Forbidden)\r
+      end\r
+    end\r
+    context '存在しないコマを開こうとしたとき' do\r
+      it '404RecordNotFound例外を返す' do\r
+        lambda{\r
+          Panel.edit 110, @author\r
+        }.should raise_error(ActiveRecord::RecordNotFound)\r
+      end\r
+    end\r
+  end\r
   describe '関連テーブルプションに於いて' do\r
     context 'オプションがないとき' do\r
-      it '4つの項目を含んでいる' do\r
-        r = Panel.show_include_opt\r
-        r.should have(4).items\r
-      end\r
-      it 'コミックを含んでいる' do\r
+      it '3つの項目を含んでいる' do\r
         r = Panel.show_include_opt\r
-        r.has_key?(:comic).should be_true\r
+        r.should have(3).items\r
       end\r
       it 'コマ絵を含んでいる' do\r
         r = Panel.show_include_opt\r
@@ -426,9 +349,9 @@ describe Panel do
       end\r
     end\r
     context 'オプションで原画を含ませたとき' do\r
-      it '5つの項目を含んでいる' do\r
+      it '4つの項目を含んでいる' do\r
         r = Panel.show_include_opt(:include => {:test => {}})\r
-        r.should have(5).items\r
+        r.should have(4).items\r
       end\r
       it 'testを含んでいる' do\r
         r = Panel.show_include_opt(:include => {:test => {}})\r
@@ -441,13 +364,9 @@ describe Panel do
       r = Panel.show_json_include_opt\r
       r.has_key?(:include).should be_true\r
     end\r
-    it '4つの項目を含んでいる' do\r
-      r = Panel.show_json_include_opt[:include]\r
-      r.should have(4).items\r
-    end\r
-    it 'コミックを含んでいる' do\r
+    it '3つの項目を含んでいる' do\r
       r = Panel.show_json_include_opt[:include]\r
-      r.has_key?(:comic).should be_true\r
+      r.should have(3).items\r
     end\r
     it 'コマ絵を含んでいる' do\r
       r = Panel.show_json_include_opt[:include]\r
@@ -484,8 +403,7 @@ describe Panel do
   end\r
   describe '一覧取得に於いて' do\r
     before do\r
-      @comic = Factory :comic, :author_id => @author.id\r
-      @panel = Factory :panel, :comic_id => @comic.id, :author_id => @author.id\r
+      @panel = Factory :panel, :author_id => @author.id\r
     end\r
     context 'page補正について' do\r
       it '文字列から数値に変換される' do\r
@@ -517,16 +435,21 @@ describe Panel do
       pl.should eq [@panel]\r
     end\r
     it '時系列で並んでいる' do\r
-      npl = Factory :panel, :comic_id => @comic.id, :author_id => @author.id, :t => 1\r
+      npl = Factory :panel, :author_id => @author.id, :updated_at => Time.now + 100\r
       pl = Panel.list\r
       pl.should eq [npl, @panel]\r
     end\r
+    it '非公開のコマは含まない' do\r
+      npl = Factory :panel, :author_id => @author.id, :publish => 0\r
+      pl = Panel.list\r
+      pl.should eq [@panel]\r
+    end\r
     context 'DBに5件あって1ページの件数を2件に変えたとして' do\r
       before do\r
-        @npl2 = Factory :panel, :comic_id => @comic.id, :author_id => @author.id, :t => 1\r
-        @npl3 = Factory :panel, :comic_id => @comic.id, :author_id => @author.id, :t => 2\r
-        @npl4 = Factory :panel, :comic_id => @comic.id, :author_id => @author.id, :t => 3\r
-        @npl5 = Factory :panel, :comic_id => @comic.id, :author_id => @author.id, :t => 4\r
+        @npl2 = Factory :panel, :author_id => @author.id, :updated_at => Time.now + 100\r
+        @npl3 = Factory :panel, :author_id => @author.id, :updated_at => Time.now + 200\r
+        @npl4 = Factory :panel, :author_id => @author.id, :updated_at => Time.now + 300\r
+        @npl5 = Factory :panel, :author_id => @author.id, :updated_at => Time.now + 400\r
         Panel.stub(:default_page_size).and_return(2)\r
       end\r
       it '通常は2件を返す' do\r
@@ -553,13 +476,9 @@ describe Panel do
       r = Panel.list_opt\r
       r.has_key?(:include).should be_true\r
     end\r
-    it '4つの項目を含んでいる' do\r
-      r = Panel.list_opt[:include]\r
-      r.should have(4).items\r
-    end\r
-    it 'コミックを含んでいる' do\r
+    it '3つの項目を含んでいる' do\r
       r = Panel.list_opt[:include]\r
-      r.has_key?(:comic).should be_true\r
+      r.should have(3).items\r
     end\r
     it 'コマ絵を含んでいる' do\r
       r = Panel.list_opt[:include]\r
@@ -599,13 +518,9 @@ describe Panel do
       r = Panel.list_json_opt\r
       r.has_key?(:include).should be_true\r
     end\r
-    it '4つの項目を含んでいる' do\r
+    it '3つの項目を含んでいる' do\r
       r = Panel.list_json_opt[:include]\r
-      r.should have(4).items\r
-    end\r
-    it 'コミックを含んでいる' do\r
-      r = Panel.list_json_opt[:include]\r
-      r.has_key?(:comic).should be_true\r
+      r.should have(3).items\r
     end\r
     it 'コマ絵を含んでいる' do\r
       r = Panel.list_json_opt[:include]\r
@@ -965,4 +880,117 @@ describe Panel do
       end\r
     end\r
   end\r
+  describe '複合チェックに於いて' do\r
+    context 'つつがなく終わるとき' do\r
+      it 'している' do\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
+        @panel.panel_pictures.build(\r
+          Factory.attributes_for(:panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id, :t => 0)\r
+        )\r
+        @panel.panel_pictures.build(\r
+          Factory.attributes_for(:panel_picture, :panel_id => @panel.id, :resource_picture_id => @rp.id, :t => 1)\r
+        )\r
+        sb1 = @panel.speech_balloons.build(\r
+          Factory.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 2)\r
+        )\r
+        sb1.balloons.build(\r
+          Factory.attributes_for(:balloon, :speech_balloon_id => sb1.id)\r
+        )\r
+        sb1.speeches.build(\r
+          Factory.attributes_for(:speech, :speech_balloon_id => sb1.id)\r
+        )\r
+        sb2 = @panel.speech_balloons.build(\r
+          Factory.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 3)\r
+        )\r
+        sb2.balloons.build(\r
+          Factory.attributes_for(:balloon, :speech_balloon_id => sb2.id)\r
+        )\r
+        sb2.speeches.build(\r
+          Factory.attributes_for(:speech, :speech_balloon_id => sb2.id)\r
+        )\r
+        r = @panel.validate_child\r
+        r.should be_true\r
+      end\r
+    end\r
+  end\r
+  describe '保存に於いて' do\r
+    context 'つつがなく終わるとき' do\r
+      it 'idチェックを依頼している' do\r
+        Panel.should_receive(:validate_elements_id).with(any_args).exactly(1)\r
+        Panel.stub(:validate_elements_id).with(any_args).and_return(true)\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
+        r = @panel.store\r
+      end\r
+      it '保存を依頼している' do\r
+        Panel.stub(:validate_elements_id).with(any_args).and_return(true)\r
+        Panel.any_instance.should_receive(:save).with(any_args).exactly(1)\r
+        Panel.any_instance.stub(:save).with(any_args).and_return(true)\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
+        r = @panel.store\r
+      end\r
+      it 'Trueを返す' do\r
+        Panel.stub(:validate_elements_id).with(any_args).and_return(true)\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
+        r = @panel.store\r
+        r.should be_true\r
+      end\r
+      it 'エラーメッセージがセットされていない' do\r
+        Panel.stub(:validate_elements_id).with(any_args).and_return(true)\r
+        @panel = Factory :panel, :author_id => @author.id\r
+        r = @panel.store\r
+        @panel.errors.empty?.should be_true\r
+      end\r
+      context '新規のとき' do\r
+        it 'Trueを返す' do\r
+          Panel.stub(:validate_elements_id).with(any_args).and_return(true)\r
+          @panel = Factory.build :panel, :author_id => @author.id\r
+          r = @panel.store\r
+          r.should be_true\r
+        end\r
+        it '行が追加されている' do\r
+          Panel.stub(:validate_elements_id).with(any_args).and_return(true)\r
+          @panel = Factory.build :panel, :author_id => @author.id\r
+          lambda {\r
+            r = @panel.store\r
+          }.should change(Panel, :count)\r
+        end\r
+      end\r
+      context '更新のとき' do\r
+        it 'Trueを返す' do\r
+          Panel.stub(:validate_elements_id).with(any_args).and_return(true)\r
+          @panel = Factory :panel, :author_id => @author.id\r
+          r = @panel.store\r
+          r.should be_true\r
+        end\r
+        it '行が追加されていない' do\r
+          Panel.stub(:validate_elements_id).with(any_args).and_return(true)\r
+          @panel = Factory :panel, :author_id => @author.id\r
+          lambda {\r
+            r = @panel.store\r
+          }.should_not change(Panel, :count)\r
+        end\r
+      end\r
+    end\r
+    context 'idチェックが失敗するとき' do\r
+      it 'Falseを返す' do\r
+        Panel.stub(:validate_elements_id).with(any_args).and_return(false)\r
+        @panel = Factory :panel, :author_id => @author.id\r
+        r = @panel.store\r
+        r.should be_false\r
+      end\r
+      it 'エラーメッセージがセットされている' do\r
+        Panel.stub(:validate_elements_id).with(any_args).and_return(false)\r
+        @panel = Factory :panel, :author_id => @author.id\r
+        r = @panel.store\r
+        @panel.errors.empty?.should be_false\r
+      end\r
+      it '行が追加されていない' do\r
+        Panel.stub(:validate_elements_id).with(any_args).and_return(false)\r
+        @panel = Factory.build :panel, :author_id => @author.id\r
+        lambda {\r
+          r = @panel.store\r
+        }.should_not change(Panel, :count)\r
+      end\r
+    end\r
+  end\r
 end\r
index 76e117c..9d91f1f 100644 (file)
@@ -279,20 +279,20 @@ describe ResourcePicture do
     end
     it '時系列で並んでいる' do
       nop = Factory :original_picture, :artist_id => @artist.id, :license_id => @license.id
-      nrp = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => nop.id
+      nrp = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => nop.id, :updated_at => Time.now + 100
       pic = ResourcePicture.list
       pic.should eq [nrp, @rp]
     end
     context 'DBに5件あって1ページの件数を2件に変えたとして' do
       before do
         nop2 = Factory :original_picture, :artist_id => @artist.id, :license_id => @license.id
-        @nrp2 = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => nop2.id
+        @nrp2 = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => nop2.id, :updated_at => Time.now + 100
         nop3 = Factory :original_picture, :artist_id => @artist.id, :license_id => @license.id
-        @nrp3 = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => nop3.id
+        @nrp3 = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => nop3.id, :updated_at => Time.now + 200
         nop4 = Factory :original_picture, :artist_id => @artist.id, :license_id => @license.id
-        @nrp4 = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => nop4.id
+        @nrp4 = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => nop4.id, :updated_at => Time.now + 300
         nop5 = Factory :original_picture, :artist_id => @artist.id, :license_id => @license.id
-        @nrp5 = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => nop5.id
+        @nrp5 = Factory :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => nop5.id, :updated_at => Time.now + 400
         ResourcePicture.stub(:default_page_size).and_return(2)
       end
       it '通常は2件を返す' do
diff --git a/spec/models/story_spec.rb b/spec/models/story_spec.rb
new file mode 100644 (file)
index 0000000..1f9a23e
--- /dev/null
@@ -0,0 +1,1341 @@
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+#ストーリー
+describe Story do
+  before do
+    Factory :admin
+    @license = Factory :license
+    @user = Factory( :user_yas)
+    @author = @user.author
+    @artist = Factory :artist_yas, :author_id => @author.id
+    @other_user = Factory( :user_yas)
+    @other_author = @other_user.author
+  end
+  
+  describe '検証に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+      @story = Factory.build :story, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+    end
+    
+    it 'オーソドックスなデータなら通る' do
+      @story.should be_valid
+    end
+    
+    context 'comic_idを検証するとき' do
+      it 'テストデータの確認' do
+        @story.comic_id = @comic.id
+        @story.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @story.comic_id = nil
+        @story.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @story.comic_id = 'a'
+        @story.should_not be_valid
+      end
+      it '存在するコミックでなければ失敗する' do
+        @story.comic_id = 0
+        @story.should_not be_valid
+      end
+    end
+    
+    context 'panel_idを検証するとき' do
+      it 'テストデータの確認' do
+        @story.panel_id = @panel.id
+        @story.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @story.panel_id = nil
+        @story.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @story.panel_id = 'a'
+        @story.should_not be_valid
+      end
+      it '存在するコマでなければ失敗する' do
+        @story.panel_id = 0
+        @story.should_not be_valid
+      end
+    end
+    
+    context 'tを検証するとき' do
+      before do
+      end
+      it 'テストデータの確認' do
+        @story.t = 0
+        @story.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @story.t = nil
+        @story.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @story.t = 'a'
+        @story.should_not be_valid
+      end
+      it '負なら失敗する' do
+        @story.t = -1
+        @story.should_not be_valid
+      end
+    end
+    
+    context 'author_idを検証するとき' do
+      it 'テストデータの確認' do
+        @story.author_id = @author.id
+        @story.should be_valid
+      end
+      it 'nullなら失敗する' do
+        @story.author_id = nil
+        @story.should_not be_valid
+      end
+      it '数値でなければ失敗する' do
+        @story.author_id = 'a'
+        @story.should_not be_valid
+      end
+      it '存在する作家でなければ失敗する' do
+        @story.author_id = 0
+        @story.should_not be_valid
+      end
+    end
+    context '全体を検証するとき' do
+      before do
+        @story = Factory :story, :author_id => @author.id
+      end
+    end
+  end
+  
+  describe 'デフォルト値補充に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+    end
+    
+    #dbのデフォルト値が0だから明示的にnilにしないと追加ができない
+    it 'tをnilにする' do
+      @story = Factory.build :story, :comic_id => @comic.id, :panel_id => @panel.id
+      @story.supply_default
+      @story.t.should be_nil
+    end
+    
+  end
+  
+  describe '上書き補充に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+    end
+    
+    context 'author_idを補充' do
+      it '問答無用でauthor_idを補充する' do
+        @story = Factory.build :story, :comic_id => @comic.id, :panel_id => @panel.id
+        @story.author_id = nil
+        @story.overwrite @author
+        @story.author_id.should eq @author.id
+      end
+    end
+    
+  end
+  
+  describe '作者判定に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+      @story = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+      @comico = Factory :comic, :author_id => @other_author.id
+      @panelo = Factory :panel, :author_id => @other_author.id
+      @storyo = Factory :story, :author_id => @other_author.id, :comic_id => @comico.id, :panel_id => @panelo.id
+    end
+    it '自分のストーリーならyes' do
+      @story.own?(@author).should == true
+    end
+    it '他人のストーリーならno' do
+      @storyo.own?(@author).should == false
+    end
+    it '作家が不明ならno' do
+      @story.own?(nil).should == false
+    end
+  end
+  describe '単体取得に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+      @story = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+    end
+    it '指定のストーリーを返す' do
+      l = Story.edit @story.id, @author
+      l.should eq @story
+    end
+    context '他人のストーリーを開こうとしたとき' do
+      it '403Forbidden例外を返す' do
+        Story.any_instance.stub(:own?).and_return(false)
+        lambda{
+          Story.edit @story.id, @author
+        }.should raise_error(ActiveRecord::Forbidden)
+      end
+    end
+    context '存在しないストーリーを開こうとしたとき' do
+      it '404RecordNotFound例外を返す' do
+        lambda{
+          Story.edit 110, @author
+        }.should raise_error(ActiveRecord::RecordNotFound)
+      end
+    end
+  end
+  
+  describe '一覧取得に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+      @story = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+      @panel2 = Factory :panel, :author_id => @author.id, :publish => 0
+    end
+    context 'offset補正について' do
+      it '文字列から数値に変換される' do
+        Story.offset(100, '8').should eq 8
+      end
+      it 'nilの場合は0になる' do
+        Story.offset(100).should eq 0
+      end
+      #投稿されたコマ数以上の値が指定されたときは、最後のコマだけになる
+      #最後のコマとは、コマ数‐1.
+      it '1件のときオフセット1なら0になる' do
+        Story.offset(1, '1').should eq 0
+      end
+      it '5件のときオフセット5なら4になる' do
+        Story.offset(5, '5').should eq 4
+      end
+      # 負の値が指定されたときは、最後のコマから数えてコマを飛ばして表示する。
+      #-4のときは、最後から4つのコマを表示する。 
+      it '2件のときオフセット-1なら1になる' do
+        Story.offset(2, '-1').should eq 1
+      end
+      it '5件のときオフセット-2なら3になる' do
+        Story.offset(5, '-2').should eq 3
+      end
+      # 最終的なが負になるなど、不正な値が入ったときは0となる。 
+      it '2件のときオフセット-5なら0になる' do
+        Story.offset(2, '-5').should eq 0
+      end
+    end
+    context 'panel_count補正について' do
+      it '文字列から数値に変換される' do
+        Story.panel_count(100, '7').should eq 7
+      end
+      it 'nilの場合はStory.default_panel_sizeになる' do
+        Story.panel_count(100).should eq Story.default_panel_size
+      end
+      it '0以下の場合はStory.default_panel_sizeになる' do
+        Story.panel_count(100, '0').should eq Story.default_panel_size
+      end
+      it 'Story.max_panel_sizeを超えた場合はStory.max_panel_sizeになる' do
+        Story.panel_count(100, '1000').should eq Story.max_panel_size
+      end
+    end
+    it 'リストを返す' do
+      c = Story.list @comic, @author
+      c.should eq [@story]
+    end
+    it 't順で並んでいる' do
+      v = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 1
+      c = Story.list @comic, @author
+      c.should eq [ @story, v]
+    end
+    it '非公開のコマは含まない' do\r
+      h = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel2.id, :t => 1
+      c = Story.list @comic, @author
+      c.should eq [ @story]
+    end\r
+    context 'DBに5件あって1ページの件数を2件に変えたとして' do
+      before do
+        @story2 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 1
+        @story3 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 2
+        @story4 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 3
+        @story5 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 4
+      end
+      it 'offset=0なら末尾2件を返す' do
+        #時系列で並んでいる
+        c = Story.list( @comic, @author, 0, 2)
+        c.should eq [@story, @story2]
+      end
+      it 'offset=2なら中間2件を返す' do
+        c = Story.list(@comic, @author, 2, 2)
+        c.should eq [@story3, @story4]
+      end
+      it 'offset=4なら先頭1件を返す' do
+        c = Story.list(@comic, @author, 4, 2)
+        c.should eq [@story5]
+      end
+    end
+  end
+  describe 'list関連テーブルプションに於いて' do
+    it 'includeキーを含んでいる' do
+      r = Story.list_opt
+      r.has_key?(:include).should be_true
+    end
+    it '3つの項目を含んでいる' do
+      r = Story.list_opt[:include]
+      r.should have(3).items
+    end
+    it 'コミックを含んでいる' do
+      r = Story.list_opt[:include]
+      r.has_key?(:comic).should be_true
+    end
+      it 'コミックは作家を含んでいる' do
+        r = Story.list_opt[:include]
+        r[:comic].has_key?(:author).should be_true
+      end
+    it '作家を含んでいる' do
+      r = Story.list_opt[:include]
+      r.has_key?(:author).should be_true
+    end
+    it 'コマを含んでいる' do
+      r = Story.list_opt[:include]
+      r.has_key?(:panel).should be_true
+    end
+      it 'コマは作家を含んでいる' do
+        r = Story.list_opt[:include]
+        r[:panel].has_key?(:author).should be_true
+      end
+      it 'コマはコマ絵を含んでいる' do
+        r = Story.list_opt[:include]
+        r[:panel].has_key?(:panel_pictures).should be_true
+      end
+      it 'コマはフキダシを含んでいる' do
+        r = Story.list_opt[:include]
+        r[:panel].has_key?(:speech_balloons).should be_true
+      end
+  end
+  describe 'json一覧出力オプションに於いて' do
+    it 'includeキーを含んでいる' do
+      r = Story.list_json_opt
+      r.has_key?(:include).should be_true
+    end
+    it '3つの項目を含んでいる' do
+      r = Story.list_json_opt[:include]
+      r.should have(3).items
+    end
+    it 'コミックを含んでいる' do
+      r = Story.list_json_opt[:include]
+      r.has_key?(:comic).should be_true
+    end
+      it 'コミックは作家を含んでいる' do
+        r = Story.list_json_opt[:include]
+        r[:comic].has_key?(:author).should be_true
+      end
+    it '作家を含んでいる' do
+      r = Story.list_json_opt[:include]
+      r.has_key?(:author).should be_true
+    end
+    it 'コマを含んでいる' do
+      r = Story.list_json_opt[:include]
+      r.has_key?(:panel).should be_true
+    end
+      it 'コマは作家を含んでいる' do
+        r = Story.list_json_opt[:include]
+        r[:panel].has_key?(:author).should be_true
+      end
+      it 'コマはコマ絵を含んでいる' do
+        r = Story.list_json_opt[:include]
+        r[:panel].has_key?(:panel_pictures).should be_true
+      end
+      it 'コマはフキダシを含んでいる' do
+        r = Story.list_json_opt[:include]
+        r[:panel].has_key?(:speech_balloons).should be_true
+      end
+  end
+  describe 't補充値に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+    end
+    
+    context 'コミック初のコマなら' do
+      it '0を補充値とする' do
+        @story = Factory.build :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+        @story.t = nil
+        r = Story.new_t @story.comic_id
+        r.should eq 0
+      end
+    end
+    context 'コミックに一個コマがあるとき' do
+      it '1を補充値とする' do
+        Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 0
+        @story = Factory.build :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+        @story.t = nil
+        r = Story.new_t @story.comic_id
+        r.should eq 1
+      end
+    end
+    context 'コミックに2個コマがあるとき' do
+      it '2を補充値とする' do
+        Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 0
+        Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 1
+        @story = Factory.build :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+        @story.t = nil
+        r = Story.new_t @story.comic_id
+        r.should eq 2
+      end
+    end
+  end
+  describe 'シリアライズチェックに於いて' do
+    context 'つつがなく終わるとき' do
+      it '0からシリアライズされているならTrueを返す' do
+        r = Story.serial? [0, 1, 2]
+        r.should be_true
+      end
+      it '見た目はシリアライズされてなくてもソート結果が無事ならtrueを返す' do
+        r = Story.serial? [0, 2, 1]
+        r.should be_true
+      end
+      it '見た目はシリアライズされてなくてもソート結果が無事ならtrueを返す' do
+        r = Story.serial? [ 2, 1, 4, 3, 0]
+        r.should be_true
+      end
+    end
+    context '異常なとき' do
+      it '0から始まらないならFalseを返す' do
+        r = Story.serial? [1, 2, 3]
+        r.should be_false
+      end
+      it '連続していないならFalseを返す' do
+        r = Story.serial? [0, 1, 2, 4]
+        r.should be_false
+      end
+      it '連続していないならFalseを返す' do
+        r = Story.serial? [0, 1, 2, 4, 5]
+        r.should be_false
+      end
+    end
+  end
+  describe 't収集に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+      @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      @comic2 = Factory :comic, :author_id => @author.id
+      @c2story = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+    end
+    context 'つつがなく終わるとき' do
+      it 'ストーリーから同一コミックのtだけを収集している' do
+        r = Story.collect_t @story
+        r.should eq [0]
+      end
+    end
+    context '複数コマのとき' do
+      it 'ストーリーから同一コミックのtだけを収集している' do
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        r = Story.collect_t @story
+        r.sort.should eq [0, 1]
+      end
+    end
+    context '複数コマでヨソのコミックも混じっているとき' do
+      it 'ストーリーから同一コミックのtだけを収集している' do
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        r = Story.collect_t @story
+        r.sort.should eq [0, 1]
+      end
+    end
+  end
+  describe 'tチェックに於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+      @story = Factory.build :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+    end
+    context 'つつがなく終わるとき' do
+      it 't収集を依頼している' do
+        Story.should_receive(:collect_t).with(any_args).exactly(1)
+        Story.stub(:collect_t).with(any_args).and_return([])
+        Story.stub(:serial?).with(any_args).and_return(true)
+        r = Story.validate_t @story
+      end
+      it '収集したtをシリアライズチェック依頼している' do
+        Story.stub(:collect_t).with(any_args).and_return([])
+        Story.should_receive(:serial?).with(any_args).exactly(1)
+        Story.stub(:serial?).with(any_args).and_return(true)
+        r = Story.validate_t @story
+      end
+    end
+    #実データでチェック
+    #依頼チェックだけでは不安なので最低限のチェックを
+    context '新規のとき' do
+      it '一件だけで正常通過している' do
+        @story = Factory.build :story, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id, :t => 0
+        r = Story.validate_t @story
+        r.should be_true 
+      end
+    end
+    context '既存のとき' do
+      it '2件目を作っても正常通過している' do
+        @story = Factory :story, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id, :t => 0
+        @story2 = Factory.build :story, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id, :t => 1
+        r = Story.validate_t @story2
+        r.should be_true 
+      end
+    end
+  end
+  describe '挿入シフトに於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+    end
+    context '依頼チェック' do
+      #テーブルが空で0に挿入
+      it 'Updateを依頼している' do
+        Story.stub(:update_all).with(any_args)
+        Story.should_receive(:update_all).with(any_args).exactly(1)
+        @story = Factory.build :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story.insert_shift
+      end
+    end
+    context 'テーブルに1件(t:0)で0に挿入したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory.build :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      end
+      it '既存の行を1にシフトしている' do
+        @story2.insert_shift
+        l = Story.find :all
+        l.first.t.should eq 1
+      end
+      it 'これから挿入するt(0)が欠番になっている' do
+        @story2.insert_shift
+        l = Story.find(:all).map {|s| s.t }
+        l.include?(0).should_not be_true
+      end
+    end
+    context 'テーブルに2件(t:0,1)で1に挿入したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory.build :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      end
+      it '既存のt1を2にシフトしてこれから挿入するt(1)が欠番になっている' do
+        @story3.insert_shift
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [0, 2]
+      end
+    end
+    context 'テーブルに5件(t:0,1,2,3,4)で2に挿入したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story6 = Factory.build :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      end
+      it '既存のt1を2にシフトしてこれから挿入するt(1)が欠番になっている' do
+        @story6.insert_shift
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [0, 1, 3, 4, 5]
+      end
+    end
+    context '先ほどのケース+他のコミック1件で挿入したとき' do
+      before do
+        @comic2 = Factory :comic, :author_id => @author.id
+        @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story6 = Factory.build :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      end
+      it '既存のt1を2にシフトしてこれから挿入するt(1)が欠番になっている' do
+        @story6.insert_shift
+        l = Story.find(:all, :conditions => ['comic_id = ?', @comic.id]).map {|s| s.t }
+        l.sort.should eq [0, 1, 3, 4, 5]
+      end
+      it '他のコミックに影響がない' do
+        ot = @storyc2.t
+        @story6.insert_shift
+        @storyc2.reload
+        @storyc2.t.should eq ot
+      end
+    end
+  end
+  describe '少ない方に移動に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+    end
+    context '依頼チェック' do
+      it 'Updateを依頼している' do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        Story.stub(:update_all).with(any_args)
+        Story.should_receive(:update_all).with(any_args).exactly(1)
+        ot = @story2.t
+        @story2.t = 0
+        @story2.lesser_shift ot
+      end
+    end
+    context 'テーブルに2件(t:0,1)で1を0に移動したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story2.t
+        @story2.t = 0
+      end
+      it '既存のt0を1にシフトしてこれから挿入するt(0)が欠番になっている' do
+        #移動させたい行はそのまま残る
+        @story2.lesser_shift @ot
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [1, 1]
+      end
+      it '既存のt0を1にシフトしている' do
+        @story2.lesser_shift @ot
+        @story.reload
+        @story.t.should eq 1
+      end
+    end
+    context 'テーブルに3件(t:0,1,2)で2を1に移動したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story3.t
+        @story3.t = 1
+      end
+      it '既存のt1を2にシフトしてこれから挿入するt(1)が欠番になっている' do
+        #移動させたい行はそのまま残る
+        @story3.lesser_shift @ot
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [0, 2, 2]
+      end
+      it '既存のt1を2にシフトしている' do
+        @story3.lesser_shift @ot
+        @story2.reload
+        @story2.t.should eq 2
+      end
+    end
+    context 'テーブルに5件(t:0,1,2,3,4)で3を1に移動したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story4.t
+        @story4.t = 1
+      end
+      it 'これから挿入するt(1)が欠番になっている' do
+        #移動させたい行はそのまま残る
+        @story4.lesser_shift @ot
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [0, 2, 3, 3, 4]
+      end
+      it '既存のt0には変化がない' do
+        @story4.lesser_shift @ot
+        @story.reload
+        @story.t.should eq 0
+      end
+      it '既存のt4には変化がない' do
+        @story4.lesser_shift @ot
+        @story5.reload
+        @story5.t.should eq 4
+      end
+      it '既存のt1を2にシフトしている' do
+        @story4.lesser_shift @ot
+        @story2.reload
+        @story2.t.should eq 2
+      end
+      it '既存のt2を3にシフトしている' do
+        @story4.lesser_shift @ot
+        @story3.reload
+        @story3.t.should eq 3
+      end
+    end
+    context '先ほどのケース+他のコミック1件で挿入したとき' do
+      before do
+        @comic2 = Factory :comic, :author_id => @author.id
+        @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story4.t
+        @story4.t = 1
+      end
+      it 'これから挿入するt(1)が欠番になっている' do
+        @story4.lesser_shift @ot
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [0, 0, 2, 3, 3, 4]
+      end
+      it '既存のt0には変化がない' do
+        @story4.lesser_shift @ot
+        @story.reload
+        @story.t.should eq 0
+      end
+      it '既存のt4には変化がない' do
+        @story4.lesser_shift @ot
+        @story5.reload
+        @story5.t.should eq 4
+      end
+      it '既存のt1を2にシフトしている' do
+        @story4.lesser_shift @ot
+        @story2.reload
+        @story2.t.should eq 2
+      end
+      it '既存のt2を3にシフトしている' do
+        @story4.lesser_shift @ot
+        @story3.reload
+        @story3.t.should eq 3
+      end
+      it '他のコミックに影響がない' do
+        @story4.lesser_shift @ot
+        @storyc2.reload
+        @storyc2.t.should eq 0
+      end
+    end
+    #例外ケース。
+    #負のときは0として正常扱い
+    context 'テーブルに2件(t:0,1)で1を-1に移動したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story2.t
+        @story2.t = -1
+      end
+      it '既存のt0を1にシフトしてこれから挿入するt(0)が欠番になっている' do
+        #移動させたい行はそのまま残る
+        @story2.lesser_shift @ot
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [1, 1]
+      end
+      it '既存のt0を1にシフトしている' do
+        @story2.lesser_shift @ot
+        @story.reload
+        @story.t.should eq 1
+      end
+      it '既存のt1は0に補正されている' do
+        @story2.lesser_shift @ot
+        @story2.t.should eq 0
+      end
+    end
+  end
+  describe '大きい方に移動に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+    end
+    context '依頼チェック' do
+      it 'Updateを依頼している' do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        Story.stub(:update_all).with(any_args)
+        Story.should_receive(:update_all).with(any_args).exactly(1)
+        ot = @story.t
+        @story.t = 1
+        @story.higher_shift ot
+      end
+    end
+    context 'テーブルに2件(t:0,1)で0を1に移動したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story.t
+        @story.t = 1
+      end
+      it '既存のt1を0にシフトしてこれから挿入するt(1)が欠番になっている' do
+        #移動させたい行はそのまま残る
+        @story.higher_shift @ot
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [0, 0]
+      end
+      it '既存のt1を0にシフトしている' do
+        @story.higher_shift @ot
+        @story2.reload
+        @story2.t.should eq 0
+      end
+    end
+    context 'テーブルに3件(t:0,1,2)で0を1に移動したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story.t
+        @story.t = 1
+      end
+      it '既存のt1を0にシフトしてこれから挿入するt(1)が欠番になっている' do
+        #移動させたい行はそのまま残る
+        @story.higher_shift @ot
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [0, 0, 2]
+      end
+      it '既存のt1を0にシフトしている' do
+        @story.higher_shift @ot
+        @story2.reload
+        @story2.t.should eq 0
+      end
+    end
+    context 'テーブルに5件(t:0,1,2,3,4)で1を3に移動したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story2.t
+        @story2.t = 3
+      end
+      it 'これから挿入するt(3)が欠番になっている' do
+        #移動させたい行はそのまま残る
+        @story2.higher_shift @ot
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [0, 1, 1, 2, 4]
+      end
+      it '既存のt0には変化がない' do
+        @story2.higher_shift @ot
+        @story.reload
+        @story.t.should eq 0
+      end
+      it '既存のt4には変化がない' do
+        @story2.higher_shift @ot
+        @story5.reload
+        @story5.t.should eq 4
+      end
+      it '既存のt2を1にシフトしている' do
+        @story2.higher_shift @ot
+        @story3.reload
+        @story3.t.should eq 1
+      end
+      it '既存のt3を2にシフトしている' do
+        @story2.higher_shift @ot
+        @story4.reload
+        @story4.t.should eq 2
+      end
+    end
+    context '先ほどのケース+他のコミック1件で挿入したとき' do
+      before do
+        @comic2 = Factory :comic, :author_id => @author.id
+        @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story2.t
+        @story2.t = 3
+      end
+      it 'これから挿入するt(3)が欠番になっている' do
+        #移動させたい行はそのまま残る
+        @story2.higher_shift @ot
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [0, 0, 1, 1, 2, 4]
+      end
+      it '既存のt0には変化がない' do
+        @story2.higher_shift @ot
+        @story.reload
+        @story.t.should eq 0
+      end
+      it '既存のt4には変化がない' do
+        @story2.higher_shift @ot
+        @story5.reload
+        @story5.t.should eq 4
+      end
+      it '既存のt2を1にシフトしている' do
+        @story2.higher_shift @ot
+        @story3.reload
+        @story3.t.should eq 1
+      end
+      it '既存のt3を2にシフトしている' do
+        @story2.higher_shift @ot
+        @story4.reload
+        @story4.t.should eq 2
+      end
+      it '他のコミックに影響がない' do
+        @story2.higher_shift @ot
+        @storyc2.reload
+        @storyc2.t.should eq 0
+      end
+    end
+    #例外ケース。
+    #max超えたときはmaxとして正常扱い
+    context 'テーブルに2件(t:0,1)で0を2に移動したとき' do
+      before do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story.t
+        @story.t = 2
+      end
+      it '既存のt1を0にシフトしてこれから挿入するt(1)が欠番になっている' do
+        #移動させたい行はそのまま残る
+        @story.higher_shift @ot
+        l = Story.find(:all).map {|s| s.t }
+        l.sort.should eq [0, 0]
+      end
+      it '既存のt1を0にシフトしている' do
+        @story.higher_shift @ot
+        @story2.reload
+        @story2.t.should eq 0
+      end
+      it '既存のt0は1に補正されている' do
+        @story.higher_shift @ot
+        @story.t.should eq 1
+      end
+    end
+  end
+  describe '入れ替えに於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+      @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+    end
+    context '新tが旧tより小さいとき' do
+      it '少ない方に移動を依頼している' do
+        Story.any_instance.stub(:lesser_shift).with(any_args)
+        Story.any_instance.should_receive(:lesser_shift).with(any_args).exactly(1)
+        ot = @story2.t
+        @story2.t = 0
+        @story2.update_shift ot
+      end
+    end
+    context '新tが旧tより大きいとき' do
+      it '大きい方に移動を依頼している' do
+        Story.any_instance.stub(:higher_shift).with(any_args)
+        Story.any_instance.should_receive(:higher_shift).with(any_args).exactly(1)
+        ot = @story.t
+        @story.t = 1
+        @story.update_shift ot
+      end
+    end
+  end
+  describe '順序入れ替えに於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+    end
+    context 'オブジェクトが新規でtが空のとき' do
+      it '末尾追加としてtを補充依頼している' do
+        @story = Factory.build :story, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        Story.stub(:new_t).with(any_args).and_return(0)
+        Story.should_receive(:new_t).with(any_args).exactly(1)
+        @story.t = nil
+        r = @story.rotate
+      end
+    end
+    context 'オブジェクトが新規でtが設定されているとき' do
+      it '挿入追加として挿入シフトを依頼している' do
+        @story = Factory.build :story, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        Story.any_instance.stub(:insert_shift).with(any_args)
+        Story.any_instance.should_receive(:insert_shift).with(any_args).exactly(1)
+        @story.t = 0
+        r = @story.rotate
+      end
+    end
+    context 'オブジェクトが新規でなくtが設定されているとき' do
+      it 'コマ移動として入れ替えを依頼している' do
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        Story.any_instance.stub(:update_shift).with(any_args)
+        Story.any_instance.should_receive(:update_shift).with(1).exactly(1)
+        @story2.t = 0
+        r = @story.rotate 1
+      end
+    end
+    context 'オブジェクトが新規でなくtが空のとき' do
+      it '入れ替えもシフトもせず、tを空のままにしている' do
+        #結果、tに欠番が生じてシリアライズチェックでひっかかる
+      end
+    end
+  end
+  describe '編集許可に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+      @story = Factory.build :story, :t => nil, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+    end
+    context 'つつがなく終わるとき' do
+      it 'trueを返す' do
+        r = @story.allow?
+        r.should be_true
+      end
+    end
+    context 'コミックで引っかかるとき' do
+      it 'falseを返す' do
+        @story.comic_id = nil
+        r = @story.allow?
+        r.should be_false
+      end
+      it 'falseを返す' do
+        Comic.any_instance.stub(:own?).with(any_args).and_return(false)
+        r = @story.allow?
+        r.should be_false
+      end
+    end
+    context 'コマで引っかかるとき' do
+      it 'falseを返す' do
+        @story.panel_id = nil
+        r = @story.allow?
+        r.should be_false
+      end
+      it 'falseを返す' do
+        Panel.any_instance.stub(:usable?).with(any_args).and_return(false)
+        r = @story.allow?
+        r.should be_false
+      end
+    end
+  end
+  describe '保存に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+      @story = Factory.build :story, :t => nil, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+    end
+    context 'つつがなく終わるとき' do
+      it '編集許可チェックを依頼している' do
+        Story.any_instance.stub(:allow?).with(any_args).and_return(true)
+        Story.any_instance.should_receive(:allow?).with(any_args).exactly(1)
+        r = @story.store
+      end
+      it '順序入れ替えを依頼している' do
+        Story.any_instance.stub(:rotate).with(any_args).and_return(0)
+        Story.any_instance.should_receive(:rotate).with(any_args).exactly(1)
+        Story.any_instance.stub(:save).with(any_args).and_return(true)
+        Story.stub(:validate_t).with(any_args).and_return(true)
+        r = @story.store 
+      end
+      it '保存を依頼している' do
+        Story.stub(:new_t).with(any_args).and_return(0)
+        Story.any_instance.stub(:save).with(any_args).and_return(true)
+        Story.any_instance.should_receive(:save).with(any_args).exactly(1)
+        Story.stub(:validate_t).with(any_args).and_return(true)
+        r = @story.store
+      end
+      it 'tのシリアライズチェックを依頼している' do
+        Story.stub(:new_t).with(any_args).and_return(0)
+        Story.any_instance.stub(:save).with(any_args).and_return(true)
+        Story.stub(:validate_t).with(any_args).and_return(true)
+        Story.should_receive(:validate_t).with(any_args).exactly(1)
+        r = @story.store
+      end
+    end
+    #入れ替えテストと同じテストを実施。こちらはシフトだけでなく本尊も更新されている
+    context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で2に挿入したとき' do
+      before do
+        @comic2 = Factory :comic, :author_id => @author.id
+        @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story6 = Factory.build :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      end
+      it '既存のt0には変化がない' do
+        @story6.store
+        @story.reload
+        @story.t.should eq 0
+      end
+      it '既存のt1には変化がない' do
+        @story6.store
+        @story2.reload
+        @story2.t.should eq 1
+      end
+      it '既存のt2を3にシフトしている' do
+        @story6.store
+        @story3.reload
+        @story3.t.should eq 3
+      end
+      it '既存のt3を4にシフトしている' do
+        @story6.store
+        @story4.reload
+        @story4.t.should eq 4
+      end
+      it '既存のt5を5にシフトしている' do
+        @story6.store
+        @story5.reload
+        @story5.t.should eq 5
+      end
+      it '新規のt2が作成されている' do
+        @story6.store
+        @story6.reload
+        @story6.t.should eq 2
+      end
+      it '他のコミックに影響がない' do
+        @ot = @storyc2.t
+        @story6.store
+        @storyc2.reload
+        @storyc2.t.should eq @ot
+      end
+    end
+    context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で3を1に移動したとき' do
+      before do
+        @comic2 = Factory :comic, :author_id => @author.id
+        @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story4.t
+        @story4.t = 1
+      end
+      it '既存のt0には変化がない' do
+        @story4.store @ot
+        @story.reload
+        @story.t.should eq 0
+      end
+      it '既存のt4には変化がない' do
+        @story4.store @ot
+        @story5.reload
+        @story5.t.should eq 4
+      end
+      it '既存のt1を2にシフトしている' do
+        @story4.store @ot
+        @story2.reload
+        @story2.t.should eq 2
+      end
+      it '既存のt2を3にシフトしている' do
+        @story4.store @ot
+        @story3.reload
+        @story3.t.should eq 3
+      end
+      it '既存のt3を1にシフトしている' do
+        @story4.store @ot
+        @story4.reload
+        @story4.t.should eq 1
+      end
+      it '他のコミックに影響がない' do
+        @story4.store @ot
+        @storyc2.reload
+        @storyc2.t.should eq 0
+      end
+    end
+    context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で1を3に移動したとき' do
+      before do
+        @comic2 = Factory :comic, :author_id => @author.id
+        @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story2.t
+        @story2.t = 3
+      end
+      it '既存のt0には変化がない' do
+        @story2.store @ot
+        @story.reload
+        @story.t.should eq 0
+      end
+      it '既存のt4には変化がない' do
+        @story2.store @ot
+        @story5.reload
+        @story5.t.should eq 4
+      end
+      it '既存のt1を3にシフトしている' do
+        @story2.store @ot
+        @story2.reload
+        @story2.t.should eq 3
+      end
+      it '既存のt2を1にシフトしている' do
+        @story2.store @ot
+        @story3.reload
+        @story3.t.should eq 1
+      end
+      it '既存のt3を2にシフトしている' do
+        @story2.store @ot
+        @story4.reload
+        @story4.t.should eq 2
+      end
+      it '他のコミックに影響がない' do
+        @story2.store @ot
+        @storyc2.reload
+        @storyc2.t.should eq 0
+      end
+    end
+    #ロールバックテスト。入れ替えが直接DBをいじるので、すべてのケースで確実にロールバックを確認する
+    context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で2に挿入したが保存に失敗したとき' do
+      before do
+        Story.any_instance.stub(:save).with(any_args).and_return(false)
+        @comic2 = Factory :comic, :author_id => @author.id
+        @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story6 = Factory.build :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      end
+      it '既存のtに変化がない' do
+        @story6.store
+        @story.reload
+        @story.t.should eq 0
+        @story2.reload
+        @story2.t.should eq 1
+        @story3.reload
+        @story3.t.should eq 2
+        @story4.reload
+        @story4.t.should eq 3
+        @story5.reload
+        @story5.t.should eq 4
+        @storyc2.reload
+        @storyc2.t.should eq 0
+      end
+      it 'falseを返す' do
+        r = @story6.store
+        r.should be_false
+      end
+    end
+    context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で3を1に移動したがシリアルチェックに失敗したとき' do
+      before do
+        Story.stub(:validate_t).with(any_args).and_return(false)
+        @comic2 = Factory :comic, :author_id => @author.id
+        @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+        @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @ot = @story4.t
+        @story4.t = 1
+      end
+      it '既存のtに変化がない' do
+        @story4.store @ot
+        @story.reload
+        @story.t.should eq 0
+        @story2.reload
+        @story2.t.should eq 1
+        @story3.reload
+        @story3.t.should eq 2
+        @story4.reload
+        @story4.t.should eq 3
+        @story5.reload
+        @story5.t.should eq 4
+        @storyc2.reload
+        @storyc2.t.should eq 0
+      end
+      it 'falseを返す' do
+        r = @story4.store @ot
+        r.should be_false
+      end
+      it 'tにエラーメッセージが入っている' do
+        @story4.store @ot
+        @story4.errors[:t].should_not be_empty
+        @story4.valid?.should be_true
+      end
+    end
+    context '編集不可だったとき' do
+      before do
+        @story = Factory.build :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        Story.any_instance.stub(:allow?).and_return(false)
+      end
+      it '403Forbidden例外を返す' do
+        lambda{
+          @story.store
+        }.should raise_error(ActiveRecord::Forbidden)
+      end
+    end
+  end
+  describe '切り詰め処理つき削除に於いて' do
+    before do
+      @comic = Factory :comic, :author_id => @author.id
+      @panel = Factory :panel, :author_id => @author.id
+      @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+    end
+    context 'つつがなく終わるとき' do
+      it '削除される' do
+        lambda{
+          @story.destroy_and_shorten
+        }.should change(Story, :count ).by(-1)
+      end
+    end
+    #連携テスト。切り詰めが直接DBをいじる
+    context '2件で先頭を削除したとき' do
+      before do
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      end
+      it '行が削除される' do
+        lambda{
+          @story.destroy_and_shorten
+        }.should change(Story, :count ).by(-1)
+      end
+      it '先頭は削除される' do
+        @story.destroy_and_shorten
+        lambda{
+          Story.find @story.id
+        }.should raise_error(ActiveRecord::RecordNotFound)
+      end
+      it '2件目は前に詰められる' do
+        @story.destroy_and_shorten
+        @story2.reload
+        @story2.t.should eq 0
+      end
+    end
+    context '3件で先頭を削除したとき' do
+      before do
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      end
+      it '行が削除される' do
+        lambda{
+          @story.destroy_and_shorten
+        }.should change(Story, :count ).by(-1)
+      end
+      it '先頭は削除される' do
+        @story.destroy_and_shorten
+        lambda{
+          Story.find @story.id
+        }.should raise_error(ActiveRecord::RecordNotFound)
+      end
+      it '2件目は前に詰められる' do
+        @story.destroy_and_shorten
+        @story2.reload
+        @story2.t.should eq 0
+      end
+      it '3件目は前に詰められる' do
+        @story.destroy_and_shorten
+        @story3.reload
+        @story3.t.should eq 1
+      end
+    end
+    context '5件で3件目を削除したとき' do
+      before do
+        @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+        @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      end
+      it '行が削除される' do
+        lambda{
+          @story3.destroy_and_shorten
+        }.should change(Story, :count ).by(-1)
+      end
+      it '1件目は変化がない' do
+        @story3.destroy_and_shorten
+        @story.reload
+        @story.t.should eq 0
+      end
+      it '2件目は変化がない' do
+        @story3.destroy_and_shorten
+        @story2.reload
+        @story2.t.should eq 1
+      end
+      it '3件目は削除される' do
+        @story3.destroy_and_shorten
+        lambda{
+          Story.find @story3.id
+        }.should raise_error(ActiveRecord::RecordNotFound)
+      end
+      it '4件目は前に詰められる' do
+        @story3.destroy_and_shorten
+        @story4.reload
+        @story4.t.should eq 2
+      end
+      it '5件目は前に詰められる' do
+        @story3.destroy_and_shorten
+        @story5.reload
+        @story5.t.should eq 3
+      end
+    end
+    #ロールバックテスト。切り詰めが直接DBをいじるので、すべてのケースで確実にロールバックを確認する
+  end
+end
diff --git a/spec/requests/comics_spec.rb b/spec/requests/comics_spec.rb
deleted file mode 100644 (file)
index 20de573..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-require 'spec_helper'
-
-describe "Comics" do
-  describe "GET /comics" do
-    it "works! (now write some real specs)" do
-      # Run the generator again with the --webrat flag if you want to use webrat methods/matchers
-      get comics_path
-      response.status.should be(200)
-    end
-  end
-end
diff --git a/spec/routing/comics_routing_spec.rb b/spec/routing/comics_routing_spec.rb
deleted file mode 100644 (file)
index 173c1ec..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-require "spec_helper"
-
-describe ComicsController do
-  describe "routing" do
-
-    it "routes to #index" do
-      get("/comics").should route_to("comics#index")
-    end
-
-    it "routes to #new" do
-      get("/comics/new").should route_to("comics#new")
-    end
-
-    it "routes to #show" do
-      get("/comics/1").should route_to("comics#show", :id => "1")
-    end
-
-    it "routes to #edit" do
-      get("/comics/1/edit").should route_to("comics#edit", :id => "1")
-    end
-
-    it "routes to #create" do
-      post("/comics").should route_to("comics#create")
-    end
-
-    it "routes to #update" do
-      put("/comics/1").should route_to("comics#update", :id => "1")
-    end
-
-    it "routes to #destroy" do
-      delete("/comics/1").should route_to("comics#destroy", :id => "1")
-    end
-
-  end
-end
diff --git a/spec/views/comics/edit.html.erb_spec.rb b/spec/views/comics/edit.html.erb_spec.rb
deleted file mode 100644 (file)
index 42357cc..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'spec_helper'
-
-describe "comics/edit.html.erb" do
-  before(:each) do
-    @comic = assign(:comic, stub_model(Comic))
-  end
-
-  it "renders the edit comic form" do
-    render
-
-    # Run the generator again with the --webrat flag if you want to use webrat matchers
-    assert_select "form", :action => comics_path(@comic), :method => "post" do
-    end
-  end
-end
diff --git a/spec/views/comics/index.html.erb_spec.rb b/spec/views/comics/index.html.erb_spec.rb
deleted file mode 100644 (file)
index 306c04c..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-require 'spec_helper'
-
-describe "comics/index.html.erb" do
-  before(:each) do
-    assign(:comics, [
-      stub_model(Comic),
-      stub_model(Comic)
-    ])
-  end
-
-  it "renders a list of comics" do
-    render
-  end
-end
diff --git a/spec/views/comics/new.html.erb_spec.rb b/spec/views/comics/new.html.erb_spec.rb
deleted file mode 100644 (file)
index d850215..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'spec_helper'
-
-describe "comics/new.html.erb" do
-  before(:each) do
-    assign(:comic, stub_model(Comic).as_new_record)
-  end
-
-  it "renders new comic form" do
-    render
-
-    # Run the generator again with the --webrat flag if you want to use webrat matchers
-    assert_select "form", :action => comics_path, :method => "post" do
-    end
-  end
-end
diff --git a/spec/views/comics/show.html.erb_spec.rb b/spec/views/comics/show.html.erb_spec.rb
deleted file mode 100644 (file)
index b0fc5f2..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-require 'spec_helper'
-
-describe "comics/show.html.erb" do
-  before(:each) do
-    @comic = assign(:comic, stub_model(Comic))
-  end
-
-  it "renders attributes in <p>" do
-    render
-  end
-end
diff --git a/vendor/plugins/pettan_importer/db/migrate/20120619100752_create_imports.rb b/vendor/plugins/pettan_importer/db/migrate/20120619100752_create_imports.rb
new file mode 100644 (file)
index 0000000..0062f35
--- /dev/null
@@ -0,0 +1,9 @@
+class CreateImports < ActiveRecord::Migration
+  def change
+    create_table :imports do |t|
+      t.integer :a
+      t.string :b, :null => false
+      t.timestamps
+    end
+  end
+end
diff --git a/vendor/plugins/pettan_importer/init.rb b/vendor/plugins/pettan_importer/init.rb
new file mode 100644 (file)
index 0000000..d7ba40a
--- /dev/null
@@ -0,0 +1 @@
+require 'pettan_importer'
diff --git a/vendor/plugins/pettan_importer/lib/pettan_importer.rb b/vendor/plugins/pettan_importer/lib/pettan_importer.rb
new file mode 100644 (file)
index 0000000..f28ce1e
--- /dev/null
@@ -0,0 +1,78 @@
+#インポート処理
+require 'common'
+
+module ActiveRecord\r
+  class Base\r
+    module PettanImporter
+      def self.included(base)
+        base.extend(ClassMethods)
+        base.__send__ :include, InstanceMethods
+      end
+      
+      module ClassMethods
+        def each_import data
+          data.each do |n, d|
+            yield n, d
+          end
+        end
+        
+        def replace_system_picture attr
+          d = attr["system_picture"]
+          return nil if d.blank?
+          sp = SystemPicture.store Base64.decode64(d.to_s)
+          return false unless sp
+          attr["system_picture_id"] = sp.id
+          attr.delete "system_picture"
+          true
+        end
+        
+        def modify_object(name, attr, key = 'name')
+          c = 'find_by_' + key.to_s
+          r = self.__send__ c, name
+          if r
+            r.attributes = attr
+          else
+            r = self.new attr
+            r[key] = name
+          end
+          r
+        end
+        
+        def import_text(data, &blk)
+          d = JSON.parse_no_except(data)
+          return false unless d
+          res = []
+          self.transaction do
+            d.each do |name, item|
+              m = blk.call(name, item)
+              res.push(m) unless m.valid?
+            end
+            raise ActiveRecord::Rollback unless res.empty?
+          end
+          res
+        end
+        
+        def import_file(filename, &blk)
+          t = nil
+          begin
+            t = File.open(filename, 'r').read
+          rescue
+            return false
+          end
+          self.import_text t, &blk
+        end
+        
+      end
+      
+      module InstanceMethods
+        private
+        
+        public
+        
+      end
+      
+    end
+    include PettanImporter
+  end
+end
+
diff --git a/vendor/plugins/pettan_importer/test/import.json b/vendor/plugins/pettan_importer/test/import.json
new file mode 100644 (file)
index 0000000..bdd519e
--- /dev/null
@@ -0,0 +1,6 @@
+{\r
+  "1": {\r
+    "a": 1,\r
+    "b": "x"\r
+  }\r
+}\r
diff --git a/vendor/plugins/pettan_importer/test/import.rb b/vendor/plugins/pettan_importer/test/import.rb
new file mode 100644 (file)
index 0000000..913ea94
--- /dev/null
@@ -0,0 +1,6 @@
+class Import < ActiveRecord::Base
+  validates :b, :presence => true
+  def store
+    
+  end
+end
diff --git a/vendor/plugins/pettan_importer/test/import_spec.rb b/vendor/plugins/pettan_importer/test/import_spec.rb
new file mode 100644 (file)
index 0000000..c13f6e4
--- /dev/null
@@ -0,0 +1,313 @@
+# -*- encoding: utf-8 -*-
+require 'spec_helper'
+require File.expand_path(File.dirname(__FILE__) + '/import')\r
+#インポート処理
+
+describe Import do
+  before do
+    @t = '{"Z": {"a": 1, "b": "Z"}}'
+    @j = JSON.parse @t
+    @ts = '{"Z": {"a": 1, "b": "Z"}, "X": {"a": 2, "b": "X"}}'
+    @js = JSON.parse @ts
+    @tes = '{"1": {"a": 0}, "2": {"a": 0}, "Z": {"a": 2, "b": "Z"}}'
+    @jes = JSON.parse @tes
+    @f = File.expand_path(File.dirname(__FILE__) + '/import.json')
+  end
+
+  describe 'システム画像置換に於いて' do
+    before do
+      @attr = {"system_picture" => 'DAt'}
+      @sp = Factory :system_picture
+    end
+    context 'つつがなく終わるとき' do
+      it 'システム画像に保存を依頼している' do
+        SystemPicture.stub(:store).with(any_args).and_return(@sp)
+        SystemPicture.should_receive(:store).with(any_args).exactly(1)
+        r = Import.replace_system_picture(@attr)
+      end
+      it 'system_pictureキーを削除している' do
+        SystemPicture.stub(:store).with(any_args).and_return(@sp)
+        r = Import.replace_system_picture(@attr)
+        @attr.has_key?("system_picture").should be_false
+      end
+      it 'system_picture_idキーを追加している' do
+        SystemPicture.stub(:store).with(any_args).and_return(@sp)
+        r = Import.replace_system_picture(@attr)
+        @attr.has_key?("system_picture_id").should be_true
+      end
+      it '値はシステム画像オブジェクトのidとしている' do
+        SystemPicture.stub(:store).with(any_args).and_return(@sp)
+        r = Import.replace_system_picture(@attr)
+        @attr["system_picture_id"].should eq @sp.id
+      end
+      it 'trueを返す' do
+        SystemPicture.stub(:store).with(any_args).and_return(@sp)
+        r = Import.replace_system_picture(@attr)
+        r.should be_true
+      end
+    end
+    context '例外ケース' do
+      it 'カラム値にsystem_pictureキーがなければnilを返す' do
+        @a = {}
+        SystemPicture.stub(:store).with(any_args).and_return(@sp)
+        r = Import.replace_system_picture(@a)
+        r.should be_nil
+      end
+      it 'カラム値のsystem_pictureキーの値が空ならばnilを返す' do
+        @a = {"system_picture" => ''}
+        SystemPicture.stub(:store).with(any_args).and_return(@sp)
+        r = Import.replace_system_picture(@a)
+        r.should be_nil
+      end
+      it 'システム画像の保存が失敗(False)ならFalseを返す' do
+        SystemPicture.stub(:store).with(any_args).and_return(false)
+        r = Import.replace_system_picture(@attr)
+        r.should be_false
+      end
+    end
+  end
+  describe '対象オブジェクトの更新準備に於いて' do
+    context 'つつがなく終わるとき' do
+      before do
+        @n = @j.keys.first
+        @a = @j.values.first
+      end
+      it 'キーカラムをnameで補充している' do
+        Import.stub(:find_by_name).with(any_args).and_return(nil)
+        Import.should_receive(:__send__).with('find_by_name', @n).exactly(1)
+        r = Import.modify_object(@n, @a)
+      end
+      it 'オブジェクト取得を依頼している' do
+        Import.stub(:find_by_b).with(any_args).and_return(nil)
+        Import.should_receive(:__send__).with('find_by_b', @n).exactly(1)
+        r = Import.modify_object(@n, @a, :b)
+      end
+      it 'カラム書き換えを依頼している' do
+        Import.create! @a
+        Import.any_instance.should_receive(:attributes=).with(any_args).exactly(1)
+        r = Import.modify_object(@n, @a, :b)
+      end
+      it 'オブジェクトを返す' do
+        Import.create! @a
+        r = Import.modify_object(@n, @a, :b)
+        r.is_a?(Import).should be_true
+      end
+    end
+    context 'キー値が一致する行がないとき' do
+      before do
+        @n = @j.keys.first
+        @a = @j.values.first
+      end
+      it '新規オブジェクトを準備して返す' do
+        r = Import.modify_object(@n, @a, :b)
+        r.should be_a_new Import
+      end
+      it 'オブジェクトが渡したデータで書き換えられている' do
+        r = Import.modify_object(@n, @a, :b)
+        r["a"].should eq 1
+        r["b"].should eq "Z"
+      end
+    end
+    context 'キー値が一致する行があるとき' do
+      before do
+        @n = @j.keys.first
+        @a = @j.values.first
+        Import.create!(@a)
+      end
+      it '該当行を返す' do
+        r = Import.modify_object(@n, {:a => 3}, :b)
+        r.is_a?(Import).should be_true
+        r.should_not be_a_new Import
+        r[:b].should eq @n
+      end
+      it 'オブジェクトが渡したデータで書き換えられている' do
+        r = Import.modify_object(@n, {:a => 3}, :b)
+        r[:a].should eq 3
+      end
+    end
+  end
+  
+  describe '繰り返し処理に於いて' do
+    before do
+    end
+    context '単体データを渡されたとき' do
+      it '一回処理' do
+        r = []
+        Import.each_import @j do |n, i|
+          r << i
+        end
+        r.size.should eq 1
+      end
+      it '一回処理' do
+        r = []
+        Import.each_import @j do |n, i|
+          r << n
+        end
+        r.first.should eq "Z"
+      end
+      it '一回処理' do
+        r = []
+        Import.each_import @j do |n, i|
+          r << i
+        end
+        r.first["a"].should eq 1
+        r.first["b"].should eq "Z"
+      end
+    end
+    context '複数を渡されたとき' do
+      it '二回処理' do
+        r = []
+        Import.each_import @js do |n, i|
+          r << i
+        end
+        r.size.should eq 2
+      end
+    end
+  end
+  
+  describe 'テキスト取り込みに於いて' do
+    #成功でTrue、パース失敗でFalse、失敗は保存エラーのモデルを配列で返す
+    before do
+    end
+    context 'つつがなく終わるとき' do
+      it 'Json解析を依頼する' do
+        JSON.should_receive(:parse_no_except).with(any_args).exactly(1)
+        JSON.stub(:parse_no_except).with(any_args).and_return(@j)
+        Import.import_text(@t) {|name, attr| Import.new(attr)}
+      end
+      it '更新を一回依頼する' do
+        JSON.stub(:parse_no_except).with(any_args).and_return(@j)
+        Import.any_instance.stub(:valid?).with(any_args).and_return(true)
+        #newでスタブを作るとインスタンス生成ができないので、テスト用スタブで
+        Import.should_receive(:etest).with(any_args).exactly(1)
+        Import.import_text(@t) {|name, attr| Import.etest ; Import.new(attr) }
+      end
+      it '[]を返す' do
+        JSON.stub(:parse_no_except).with(any_args).and_return(@j)
+        Import.any_instance.stub(:valid?).with(any_args).and_return(true)
+        Import.import_text(@t) {|name, attr| Import.new(attr)}.should eq []
+      end
+    end
+    context '複数データがつつがなく終わるとき' do
+      it 'ライセンス更新を二回依頼する' do
+        JSON.stub(:parse_no_except).with(any_args).and_return(@js)
+        Import.any_instance.stub(:valid?).with(any_args).and_return(true)
+        #newでスタブを作るとインスタンス生成ができないので、テスト用スタブで
+        Import.should_receive(:etest).with(any_args).exactly(2)
+        Import.import_text(@ts) {|name, attr| Import.etest ; Import.new(attr)}.should eq []
+      end
+      it '[]を返す' do
+        Import.import_text(@ts) {|name, attr| Import.new(attr)}.should eq []
+      end
+    end
+    #例外ケース
+    context 'Json解析に失敗したとき' do
+      before do
+        JSON.stub(:parse_no_except).with(any_args).and_return(false)
+      end
+      it 'Falseを返す' do
+        Import.import_text(@t){|name, attr| Import.new(attr)}.should be_false
+      end
+    end
+    context '作成に失敗したとき' do
+      before do
+        Import.any_instance.stub(:valid?).with(any_args).and_return(false)
+      end
+      it '配列を返す' do
+        r = Import.import_text(@t){|name, attr| Import.new(attr)}
+        r.is_a?(Array).should be_true
+      end
+      it '配列の中身は一件' do
+        r = Import.import_text(@t){|name, attr| Import.new(attr)}
+        r.should have(1).items
+      end
+      it 'オブジェクトが入っている' do
+        r = Import.import_text(@t){|name, attr| Import.new(attr)}
+        r.first.is_a?(Import).should be_true
+      end
+    end
+    context '複数の作成に失敗したとき' do
+      #三件中、二件の失敗、一件を成功させ、成功データは戻り値に含まないことを確認する
+      it '行の数に変化がない' do
+        lambda {
+          Import.import_text(@tes){|name, attr| Import.create(attr)}
+        }.should_not change Import, :count
+      end
+      it '途中で保存に失敗しても全件更新依頼する' do
+        Import.import_text(@tes){|name, attr| Import.create(attr)}
+      end
+      it '配列を返す' do
+        r = Import.import_text(@tes){|name, attr| Import.create(attr)}
+        r.is_a?(Array).should be_true
+      end
+      it '配列の中身は2件' do
+        r = Import.import_text(@tes){|name, attr| Import.create(attr)}
+        r.should have(2).items
+      end
+      it '配列の中身は失敗したオブジェクトが入っている' do
+        r = Import.import_text(@tes){|name, attr| Import.create(attr)}
+        r[0].is_a?(Import).should be_true
+        r[0]["a"].should eq 0
+        r[1].is_a?(Import).should be_true
+        r[1]["a"].should eq 0
+      end
+    end
+  end
+  
+  describe 'インポートエラーの表示に於いて' do
+  end
+  
+  describe 'ファイル取り込みに於いて' do
+    before do
+      Import.stub(:import).with(any_args).and_return(true)
+    end
+    context 'つつがなく終わるとき' do
+      before do
+        Import.stub(:import).with(any_args).and_return(true)
+      end
+      it 'ファイルを開いてテキストを読む' do
+        File.should_receive(:open).with(@f, 'r').exactly(1)
+        Import.import_file(@f){|name, attr| Import.new(attr) }
+      end
+      it 'テキスト取り込みを依頼する' do
+        Import.should_receive(:import_text).with(any_args).exactly(1)
+        Import.import_file(@f){|name, attr| Import.new(attr) }
+      end
+      it 'ブロックがあるとき更新を一回依頼する' do
+        Import.any_instance.stub(:valid?).with(any_args).and_return(true)
+        #newでスタブを作るとインスタンス生成ができないので、テスト用スタブで
+        Import.should_receive(:etest).with(any_args).exactly(1)
+        Import.import_file(@f) {|name, attr| Import.etest ; Import.new(attr) }
+      end
+      #テキスト取り込み成功でTrueが返る
+      it 'Trueを返す' do
+        Import.import_file(@f){|name, attr| Import.new(attr) }.should be_true
+      end
+    end
+    context 'ファイルが開けないとき' do
+      before do
+        File.stub(:open).with(any_args).and_raise('StandardError')
+      end
+      it 'ファイルエラーのメッセージを出力する' do
+        pending
+      end
+      it 'Falseを返す' do
+        Import.import_file(@f){|name, attr| Import.new(attr) }.should be_false
+      end
+    end
+    #失敗したときは、失敗したライセンスが配列で返る
+    context 'テキスト取り込みが失敗したとき' do
+      before do
+        Import.stub(:import_text).with(any_args).and_return(false)
+      end
+      it '各コモンライセンスのエラーメッセージを出力する' do
+        pending
+      end
+      it 'Falseを返す' do
+        Import.import_file(@f) {|name, attr| Import.new(attr) }.should be_false
+      end
+    end
+  end
+  
+end
+