OSDN Git Service

t#29400
authoryasushiito <yas@pen-chan.jp>
Tue, 25 Sep 2012 23:34:13 +0000 (08:34 +0900)
committeryasushiito <yas@pen-chan.jp>
Tue, 25 Sep 2012 23:34:13 +0000 (08:34 +0900)
28 files changed:
app/controllers/ground_pictures_controller.rb
app/controllers/home_controller.rb
app/controllers/original_pictures_controller.rb
app/controllers/panels_controller.rb
app/controllers/speech_balloon_templates_controller.rb
app/controllers/stories_controller.rb
app/models/original_picture.rb
app/models/panel.rb
app/models/resource_picture.rb
app/models/story.rb
app/views/comics/_form.html.erb
app/views/comics/index.html.erb
app/views/layouts/test.html.erb
app/views/speech_balloon_templates/index.html.erb
app/views/stories/comic.html.erb [new file with mode: 0644]
app/views/stories/show.html.erb
config/routes.rb
spec/cli/u/comics/create.json
spec/cli/u/original_pictures/create.json
spec/cli/u/panels/create.json
spec/cli/u/stories/create.json
spec/controllers/home_controller_spec.rb
spec/controllers/panels_controller_spec.rb
spec/controllers/stories_controller_spec.rb
spec/models/comic_spec.rb
spec/models/panel_picture_spec.rb
spec/models/panel_spec.rb
spec/models/story_spec.rb

index 28de171..aa23e7f 100644 (file)
@@ -7,7 +7,7 @@ class GroundPicturesController < ApplicationController
   def index
     @page = GroundPicture.page params[:page]
     @page_size = GroundPicture.page_size params[:page_size]
   def index
     @page = GroundPicture.page params[:page]
     @page_size = GroundPicture.page_size params[:page_size]
-    @ground_pictures = GroundPicture.list({}, @page, @page_size)
+    @ground_pictures = GroundPicture.list(@page, @page_size)
 
     respond_to do |format|
       format.html # index.html.erb
 
     respond_to do |format|
       format.html # index.html.erb
index baf9300..9d296c1 100644 (file)
@@ -86,7 +86,7 @@ class HomeController < ApplicationController
 
     respond_to do |format|
       format.html # index.html.erb
 
     respond_to do |format|
       format.html # index.html.erb
-      format.json { render json: @panels.to_json(Panel.list_json_opt) }
+      format.json { render json: @panels.to_json() }
     end
   end
   
     end
   end
   
index 1896730..6cd3400 100644 (file)
@@ -109,11 +109,12 @@ class OriginalPicturesController < ApplicationController
   # PUT /original_pictures/1
   # PUT /original_pictures/1.json
   def update
   # PUT /original_pictures/1
   # PUT /original_pictures/1.json
   def update
-    @picture_data = set_image params[:original_picture][:file]
+    @imager = PettanImager.load set_image params[:original_picture][:file]
     @original_picture = OriginalPicture.edit(params[:id], @author)
     @original_picture = OriginalPicture.edit(params[:id], @author)
+    @original_picture.overwrite @artist
 
     respond_to do |format|
 
     respond_to do |format|
-      if @original_picture.store(@picture_data, @artist)
+      if @original_picture.store(@imager)
         format.html { redirect_to @original_picture, notice: 'Original picture was successfully created.' }
         format.json { render json: @original_picture.to_json(OriginalPicture.show_json_opt), status: :created, location: @original_picture }
       else
         format.html { redirect_to @original_picture, notice: 'Original picture was successfully created.' }
         format.json { render json: @original_picture.to_json(OriginalPicture.show_json_opt), status: :created, location: @original_picture }
       else
index 29390ce..a138cba 100644 (file)
@@ -10,11 +10,11 @@ class PanelsController < ApplicationController
   def index
     @page = Panel.page params[:page]
     @page_size = Panel.page_size params[:page_size]
   def index
     @page = Panel.page params[:page]
     @page_size = Panel.page_size params[:page_size]
-    @panels = Panel.list({}, @page, @page_size)
+    @panels = Panel.list(@page, @page_size)
 
     respond_to do |format|
       format.html # index.html.erb
 
     respond_to do |format|
       format.html # index.html.erb
-      format.json { render json: @panels.to_json(Panel.list_json_opt) }
+      format.json { render text: '[' + @panels.map {|i| i.panel_elements_as_json }.join(',') + ']' }
     end
   end
 
     end
   end
 
@@ -25,9 +25,9 @@ class PanelsController < ApplicationController
 
     respond_to do |format|
       format.html # show.html.erb
 
     respond_to do |format|
       format.html # show.html.erb
-      format.json { render json: @panel.to_json(Panel.show_json_include_opt) }
+      format.json { render json: @panel.panel_elements_as_json }
       format.jsonp {
       format.jsonp {
-        render :json => "callback(" + @panel.to_json(Panel.show_json_include_opt) + ");"
+        render :json => "callback(" + @panel.panel_elements_as_json + ");"
       }
     end
   end
       }
     end
   end
@@ -63,7 +63,7 @@ class PanelsController < ApplicationController
     respond_to do |format|
       format.html # new.html.erb
       format.js
     respond_to do |format|
       format.html # new.html.erb
       format.js
-      format.json { render json: @panel }
+      format.json { render json: @panel.panel_elements_as_json }
     end
   end
 
     end
   end
 
@@ -80,16 +80,15 @@ class PanelsController < ApplicationController
   def create
     @panel = Panel.new
     @panel.supply_default
   def create
     @panel = Panel.new
     @panel.supply_default
+    jsn = nil
     if params[:json]
     if params[:json]
-      jsn = JSON.parse(params[:json])
+      jsn = JSON.parse_no_except(params[:json])
     end
     @prm = params[:panel] || jsn
     end
     @prm = params[:panel] || jsn
-    @panel.attributes = @prm
-    @panel.overwrite @author
     respond_to do |format|
     respond_to do |format|
-      if @panel.store
+      if @panel.store @prm, @author
         format.html { redirect_to @panel, notice: 'Panel was successfully created.' }
         format.html { redirect_to @panel, notice: 'Panel was successfully created.' }
-        format.json { render json: @panel, status: :created, location: @panel }
+        format.json { render json: @panel.panel_elements_as_json, status: :created, location: @panel }
       else
         format.html { render action: "new" }
         format.json { render json: @panel.errors, status: :unprocessable_entity }
       else
         format.html { render action: "new" }
         format.json { render json: @panel.errors, status: :unprocessable_entity }
@@ -101,14 +100,13 @@ class PanelsController < ApplicationController
   # PUT /panels/1.json
   def update
     @panel = Panel.edit(params[:id], @author)
   # PUT /panels/1.json
   def update
     @panel = Panel.edit(params[:id], @author)
+    jsn = nil
     if params[:json]
       jsn = JSON.parse(params[:json])
     end
     @prm = params[:panel] || jsn
     if params[:json]
       jsn = JSON.parse(params[:json])
     end
     @prm = params[:panel] || jsn
-    @panel.attributes = @prm
-    @panel.overwrite @author
     respond_to do |format|
     respond_to do |format|
-      if @panel.store
+      if @panel.store @prm, @author
         format.html { redirect_to @panel, notice: 'Panel was successfully updated.' }
         format.json { head :ok }
       else
         format.html { redirect_to @panel, notice: 'Panel was successfully updated.' }
         format.json { head :ok }
       else
index 1cbe2b8..b84c68a 100644 (file)
@@ -1,4 +1,5 @@
 class SpeechBalloonTemplatesController < ApplicationController
 class SpeechBalloonTemplatesController < ApplicationController
+  layout 'test' if Pettanr::TestLayout
   before_filter :authenticate_user!, :only => [:index, :show]
   before_filter :authenticate_admin!, :only => [:list, :browse, :destroy]
 
   before_filter :authenticate_user!, :only => [:index, :show]
   before_filter :authenticate_admin!, :only => [:list, :browse, :destroy]
 
index 4f41dc1..adbbc20 100644 (file)
@@ -3,20 +3,29 @@ class StoriesController < ApplicationController
   if Const.run_mode == 0
     before_filter :authenticate_user!, :only => [:new, :create, :edit, :update, :destroy]
   else
   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]
+    before_filter :authenticate_user!, :only => [:index, :show, :comic, :new, :create, :edit, :update, :destroy]
   end
   before_filter :authenticate_admin!, :only => [:list, :browse]
 
   def show
   end
   before_filter :authenticate_admin!, :only => [:list, :browse]
 
   def show
+    @story = Story.show(params[:id], @author)
+
+    respond_to do |format|
+      format.html # show.html.erb
+      format.json { render json: @story.story_as_json(@author) }
+    end
+  end
+  
+  def comic
     @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]
     @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)
+    @stories = Story.play_list(@comic, @author, @offset, @panel_count)
     respond_to do |format|
       format.html # index.html.erb
       format.json {
     respond_to do |format|
       format.html # index.html.erb
       format.json {
-        render :json => @stories.to_json_list
+        render :json => '[' + @stories.map {|i| i.story_as_json(@author)}.join(',') + ']'
       }
       format.jsonp {
         render :json => "callback(" + @stories.to_json_list + ");"
       }
       format.jsonp {
         render :json => "callback(" + @stories.to_json_list + ");"
@@ -51,7 +60,7 @@ class StoriesController < ApplicationController
     respond_to do |format|
       format.html # new.html.erb
       format.js
     respond_to do |format|
       format.html # new.html.erb
       format.js
-      format.json { render json: @story }
+      format.json { render json: @story.story_as_json(@author) }
     end
   end
 
     end
   end
 
@@ -72,11 +81,13 @@ class StoriesController < ApplicationController
     @story.supply_default
     @story.attributes = params[:story]
     @story.overwrite @author
     @story.supply_default
     @story.attributes = params[:story]
     @story.overwrite @author
+    @comic = Comic.edit(@story.comic_id, @author)
+    @panel = Panel.show(@story.panel_id, @author)
     
     respond_to do |format|
       if @story.store
     
     respond_to do |format|
       if @story.store
-        format.html { redirect_to action: :show, id: @story.comic_id }
-        format.json { render json: @story.to_json() }
+        format.html { redirect_to action: :comic, id: @story.comic_id }
+        format.json { render json: @story.story_as_json(@author) }
       else
         format.html { render action: "new" }
         format.json { render json: @story.errors, status: :unprocessable_entity }
       else
         format.html { render action: "new" }
         format.json { render json: @story.errors, status: :unprocessable_entity }
@@ -93,7 +104,7 @@ class StoriesController < ApplicationController
     @story.overwrite @author
     respond_to do |format|
       if @story.store ot
     @story.overwrite @author
     respond_to do |format|
       if @story.store ot
-        format.html { redirect_to action: :show, id: @story.comic_id }
+        format.html { redirect_to action: :comic, id: @story.comic_id }
         format.json { head :ok }
       else
         format.html { render action: "edit" }
         format.json { head :ok }
       else
         format.html { render action: "edit" }
index bd776a6..534e337 100644 (file)
@@ -41,7 +41,7 @@ class OriginalPicture < ActiveRecord::Base
   end
   
   def opt_img_tag
   end
   
   def opt_img_tag
-    tw, th = ResourcePicture.fix_size_both(MagicNumber['thumbnail_width'], MagicNumber['thumbnail_height'], self.width, self.height)
+    tw, th = PettanImager.thumbnail_size(self.width, self.height)
     {:src => self.url, :width => tw, :height => th}
   end
   
     {:src => self.url, :width => tw, :height => th}
   end
   
index db740ff..e9424b1 100644 (file)
@@ -21,91 +21,33 @@ class Panel < ActiveRecord::Base
   validates :y, :numericality => {:allow_blank => true}
   validates :z, :numericality => {:allow_blank => true, :greater_than => 0}
   validates :author_id, :presence => true, :numericality => true, :existence => true
   validates :y, :numericality => {:allow_blank => true}
   validates :z, :numericality => {:allow_blank => true, :greater_than => 0}
   validates :author_id, :presence => true, :numericality => true, :existence => true
+  validates :publish, :presence => true, :numericality => true
   
   def supply_default
     self.border = 2
   
   def supply_default
     self.border = 2
+    self.publish = 0
   end
   
   def overwrite au
   end
   
   def overwrite au
-    return false unless au
     self.author_id = au.id
   end
   
     self.author_id = au.id
   end
   
-  def self.collect_element_value elements, name, ex_nil = false
-    e = elements.map {|e|
-      e.map {|o|
-        o[name]
-      }
-    }.flatten
-    e = e.compact if ex_nil
-    e
-  end
-  
-  def self.validate_id ary, pid
-    ary.map {|v|
-      if pid
-        (v == pid or v == nil) ? nil : false
-      else
-        v ? false : nil
-      end
-    }.compact.empty?
-  end
-  
-  def self.validate_element_id elements, name, pid
-    Panel.validate_id(Panel.collect_element_value(elements, name), pid)
-  end
-  
-  def self.validate_elements_id c
-    c.map {|conf|
-      Panel.validate_element_id(conf[:elements], conf[:name], conf[:parent_id]) ? nil : false
-    }.compact.empty?
-  end
-  
-  def self.validate_t 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_element_t elements, name
-    Panel.validate_t(Panel.collect_element_value(elements, name, true))
-  end
-  
-  def self.validate_elements_t c
-    c.map {|conf|
-      Panel.validate_element_t(conf[:elements], conf[:name]) ? nil : false
-    }.compact.empty?
+  def visible? au
+    return false unless au
+    self.own?(au) or self.publish?
   end
   
   end
   
-  def validate_id_list
-    r = self.speech_balloons.map {|sb|
-      {:elements => [sb.speeches, sb.balloons], :name => :speech_balloon_id, :parent_id => sb.id}
-    }
-    r.unshift({:elements => [self.panel_pictures, self.speech_balloons], :name => :panel_id, :parent_id => self.id})
-    r
+  def own? au
+    return false unless au
+    self.author_id == au.id
   end
   
   end
   
-  def validate_child
-    r1 = Panel.validate_elements_id validate_id_list
-    r2 = Panel.validate_elements_t [
-      {:elements => [self.panel_pictures, self.speech_balloons], :name => :t}
-    ]
-    r1 and r2
+  def usable? au
+    visible? au
   end
   
   end
   
-  def store
-    res = false
-    Panel.transaction do
-      unless validate_child
-        self.errors.add :base , 'invalid time'
-        raise ActiveRecord::Rollback
-      end
-      res = self.save
-    end
-    res
+  def publish?
+    self.publish > 0
   end
   
   def self.default_page_size
   end
   
   def self.default_page_size
@@ -129,17 +71,11 @@ class Panel < ActiveRecord::Base
     page_size
   end
   
     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.list opt = {}, page = 1, page_size = self.default_page_size
-    opt.merge!(self.list_opt) unless opt[:include]
-    opt.merge!({:conditions => 'panels.publish > 0', :order => 'panels.updated_at desc', :limit => page_size, :offset => (page -1) * page_size})
+  def self.list page = 1, page_size = self.default_page_size
+    opt = {}
+    opt.merge!(self.list_opt)
+    opt.merge!({:limit => page_size, :offset => (page -1) * page_size}) if page_size > 0
+    opt.merge!({:conditions => 'panels.publish > 0', :order => 'panels.updated_at desc'})
     Panel.find(:all, opt)
   end
   
     Panel.find(:all, opt)
   end
   
@@ -161,7 +97,31 @@ class Panel < ActiveRecord::Base
     }}
   end
   
     }}
   end
   
-  def self.list_json_opt
+  def self.mylist au, page = 1, page_size = Author.default_panel_page_size
+    opt = {}
+    opt.merge!(self.list_opt)
+    opt.merge!({:limit => page_size, :offset => (page -1) * page_size}) if page_size > 0
+    opt.merge!({:conditions => ['panels.author_id = ?', au.id], :order => 'panels.updated_at desc'})
+    Panel.find(:all, opt)
+  end
+  
+  def self.show rid, au
+    opt = {}
+    opt.merge!(Panel.show_opt)
+    res = Panel.find(rid, opt)
+    raise ActiveRecord::Forbidden unless res.visible?(au)
+    res
+  end
+  
+  def self.edit rid, au
+    opt = {}
+    opt.merge!(Panel.show_opt)
+    res = Panel.find(rid, opt)
+    raise ActiveRecord::Forbidden unless res.own?(au)
+    res
+  end
+  
+  def self.show_opt
     {:include => {
       :panel_pictures => {
         :picture => {:artist => {}, :license => {}}
     {:include => {
       :panel_pictures => {
         :picture => {:artist => {}, :license => {}}
@@ -179,133 +139,143 @@ class Panel < ActiveRecord::Base
     }}
   end
   
     }}
   end
   
-  def self.mylist au, opt = {}, page = 1, panel_page_size = Author.default_panel_page_size
-    opt.merge!(self.list_opt) unless opt[:include]
-    opt.merge!({:conditions => ['panels.author_id = ?', au.id], :order => 'panels.updated_at desc', :limit => panel_page_size, :offset => (page -1) * page_size})
-    Panel.find(:all, opt)
+  def parts_element
+    ((self.panel_pictures || []) + (self.speech_balloons || [])).compact
   end
   
   end
   
-  def self.show rid, au, opt = {}
-    r = Panel.find(rid, :include => self.show_include_opt(opt))
-    raise ActiveRecord::Forbidden unless r.visible?(au)
-    r
+  def parts
+    res = []
+    self.parts_element.each do |e|
+      res[e.t] = e
+    end
+    res
   end
   
   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
+  def grounds
+    ((self.ground_colors || []) + (self.ground_pictures || []) + (self.panel_colors || [])).compact
   end
   
   end
   
-  def self.show_include_opt opt = {}
-    res = {
-      :panel_pictures => {
-        :picture => {:artist => {}, :license => {}}
-      }, 
-      :speech_balloons => {:balloons => {}, :speeches => {}},
-      :ground_pictures => {
-        :picture => {:artist => {}, :license => {}}
-      }, 
-      :ground_colors => {
-        :color => {}
-      }, 
-      :panel_colors => {
-      }, 
-      :author => {}
+  def panel_elements
+    parts + grounds
+  end
+  
+  @@elm_json_opt = {
+    'PanelPicture' => {
+      :picture => {:artist => {}, :license => {}}
+    }, 
+    'SpeechBalloon' => {:balloons => {}, :speeches => {}},
+    'GroundPicture' => {
+      :picture => {:artist => {}, :license => {}}
+    }, 
+    'GroundColor' => {
+      :color => {}
+    }, 
+    'PanelColor' => {
+    } 
+  }
+  
+  def self.elm_json_opt e
+    @@elm_json_opt[e.class.to_s]
+  end
+  
+  def elements
+    self.panel_elements.map {|e|
+      #(-_-;)<... kore wa hidoi
+      JSON.parse e.to_json({:include => Panel.elm_json_opt(e)})
     }
     }
-    res.merge!(opt[:include]) if opt[:include]
-    res
   end
   
   end
   
-  def self.show_json_include_opt
-    {:include => {
-      :panel_pictures => {
-        :picture => {:artist => {}, :license => {}}
-      }, 
-      :speech_balloons => {:balloons => {}, :speeches => {}},
-      :ground_pictures => {
-        :picture => {:artist => {}, :license => {}}
-      }, 
-      :ground_colors => {
-        :color => {}
-      }, 
-      :panel_colors => {
-      }, 
-      :author => {}
-    }}
+  def panel_elements_as_json
+    self.to_json({:include => {:author => {}}, :methods => :elements})
   end
   
   end
   
-  def visible? au
-    return false unless au
-    self.own?(au) or self.publish?
+  def self.visible_count
+    Panel.count
   end
   
   end
   
-  def own? author
-    return false unless author
-    self.author_id == author.id
+  def self.collect_element_value elements, name
+    elements.map {|e|
+      e.map {|o|
+        o[name]
+      }
+    }.flatten
   end
   
   end
   
-  def usable? au
-    visible? au
+  def self.validate_t ary
+    i = 0
+    ary.compact.sort.each do |t|
+      break false unless t == i
+      i += 1
+    end
+    ary.compact.size == i
   end
   
   end
   
-  def publish?
-    self.publish > 0
+  def self.validate_element_t elements, name
+    Panel.validate_t(Panel.collect_element_value(elements, name))
   end
   
   end
   
-  def sort_by_time
-    pe = []
-    self.panel_pictures.each do |picture|
-      pe[picture.t] = picture
-    end
-    self.speech_balloons.each do |sb|
-      pe[sb.t] = sb
-    end
-    pe
+  def self.validate_elements_t c
+    c.map {|conf|
+      Panel.validate_element_t(conf[:elements], conf[:name]) ? nil : false
+    }.compact.empty?
   end
   
   end
   
-  def each_ground
-    (self.ground_colors || []) + (self.ground_pictures || []) + (self.panel_colors || []).each do |e|
-      yield e
-    end
+  def validate_t_list
+    [
+      {:elements => [self.panel_pictures, self.speech_balloons], :name => :t}
+    ]
   end
   end
-  
-  def each_element
-    self.sort_by_time.each do |e|
-      yield e
-    end
+  def validate_child
+#    r1 = Panel.validate_elements_id validate_id_list
+    Panel.validate_elements_t validate_t_list
   end
   
   end
   
-  def panel_elements
-    res = []
-    self.each_element do |elm|
-      if elm.kind_of?(PanelPicture)
-        res[elm.t] = elm.to_json({:include => {:picture => {:artist => {}, :license => {}}}})
-      end
-      if elm.kind_of?(SpeechBalloon)
-        res[elm.t] = elm.to_json({:include => {:balloons => {}, :speeches => {}}})
-      end
+  def store attr, au
+    if attr == false
+      self.errors.add :base, 'invalid json'
+      return false
     end
     end
-    self.each_ground do |elm|
-      if elm.kind_of?(GroundColor)
-        res <<  elm.to_json({:include => :color})
-      end
-      if elm.kind_of?(GroundPicture)
-        res << elm.to_json({:include => {:picture => {:artist => {}, :license => {}}}})
-      end
-      if elm.kind_of?(PanelColor)
-        res << elm.to_json({:include => {}})
+    self.attributes = attr
+    self.overwrite au
+    res = false
+    Panel.transaction do
+      unless validate_child
+        self.errors.add :base , 'invalid time'
+        raise ActiveRecord::Rollback
       end
       end
+      res = self.save
     end
     res
   end
   
     end
     res
   end
   
-  def to_json_play
-    self.to_json :methods => :panel_elements
+=begin\r
+  def self.validate_id ary, pid
+    ary.map {|v|
+      if pid
+        (v == pid or v == nil) ? nil : false
+      else
+        v ? false : nil
+      end
+    }.compact.empty?
+  end
+  
+  def self.validate_element_id elements, name, pid
+    Panel.validate_id(Panel.collect_element_value(elements, name), pid)
   end
   
   end
   
-  def self.visible_count
-    Panel.count
+  def self.validate_elements_id c
+    c.map {|conf|
+      Panel.validate_element_id(conf[:elements], conf[:name], conf[:parent_id]) ? nil : false
+    }.compact.empty?
+  end
+  
+  def validate_id_list
+    r = self.speech_balloons.map {|sb|
+      {:elements => [sb.speeches, sb.balloons], :name => :speech_balloon_id, :parent_id => sb.id}
+    }
+    r.unshift({:elements => [self.panel_pictures, self.speech_balloons], :name => :panel_id, :parent_id => self.id})
+    r
   end
   end
+=end
   
 end
   
 end
index 94c43c1..7bd555c 100644 (file)
@@ -72,7 +72,7 @@ class ResourcePicture < ActiveRecord::Base
   end
   
   def opt_img_tag
   end
   
   def opt_img_tag
-    tw, th = ResourcePicture.fix_size_both(MagicNumber['thumbnail_width'], MagicNumber['thumbnail_height'], self.width, self.height)
+    tw, th = PettanImager.thumbnail_size(self.width, self.height)
     {:src => self.url, :width => tw, :height => th}
   end
   
     {:src => self.url, :width => tw, :height => th}
   end
   
index df03c85..46ce75e 100644 (file)
@@ -22,12 +22,6 @@ class Story < ActiveRecord::Base
     self.author_id == author.id
   end
   
     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.default_panel_size
     30
   end
   def self.default_panel_size
     30
   end
@@ -51,11 +45,11 @@ class Story < ActiveRecord::Base
     count
   end
   
     count
   end
   
-  def self.list comic, author, offset = 0, limit = Story.default_panel_size
+  def self.play_list comic, author, offset = 0, limit = Story.default_panel_size
     opt = {}
     opt.merge!(Story.list_opt)
     opt.merge!({:offset => offset, :limit => limit}) if limit > 0
     opt = {}
     opt.merge!(Story.list_opt)
     opt.merge!({:offset => offset, :limit => limit}) if limit > 0
-    opt.merge!({:conditions => ['stories.comic_id = ? and comics.visible > 0 and panels.publish > 0', comic.id], :order => 'stories.t'})
+    opt.merge!({:conditions => ['stories.comic_id = ?', comic.id], :order => 'stories.t'})
     Story.find(:all, opt)
   end
   
     Story.find(:all, opt)
   end
   
@@ -95,8 +89,39 @@ class Story < ActiveRecord::Base
     Story.find(:all, opt)
   end
   
     Story.find(:all, opt)
   end
   
-  def to_json_list
-    self.to_json( :include => {:author => {}, :panels => {:methods => :panel_element}})
+  def self.edit sid, au
+    opt = {}
+    opt.merge!(Story.show_opt)
+    res = Story.find sid, opt
+    raise ActiveRecord::Forbidden unless res.own?(au)
+    res
+  end
+  
+  def self.show_opt
+    {:include => {
+      :author => {}, 
+      :comic => {
+        :author => {}
+      }, 
+      :panel => {
+        :author => {}, 
+        :panel_pictures => {:picture => {:artist => {}, :license => {}}}, 
+        :speech_balloons =>{:balloons => {}, :speeches => {}}
+      }
+    }}
+  end
+  
+  def elements
+    self.panel.elements
+  end
+  
+  def story_as_json au
+    panel_include = if self.panel and self.panel.visible?(au)
+      {:include => {:author => {}}, :methods => :elements}
+    else
+      {:include => {:author => {}}}
+    end
+    self.to_json({:include => {:comic => {:include => {:author => {}}}, :author => {}, :panel => panel_include}})
   end
   
   def self.new_t comic_id
   end
   
   def self.new_t comic_id
index 21a7d4f..636f7fd 100644 (file)
@@ -17,7 +17,7 @@
   </div>
   <div class="field">
     <%= f.label :visible %><br />
   </div>
   <div class="field">
     <%= f.label :visible %><br />
-    <%= f.collection_select :visible, [['only me', 0], ['everyone', 3]], :last, :first, :html => {:selected => @comic.visible} %>
+    <%= f.collection_select :visible, [['only me', 0], ['everyone', 1]], :last, :first, :html => {:selected => @comic.visible} %>
   </div>
 
   <div class="actions">
   </div>
 
   <div class="actions">
index 5ea6d81..246b92e 100644 (file)
@@ -3,7 +3,7 @@
 <% @comics.each do |comic| %>
   <div>
     <div>
 <% @comics.each do |comic| %>
   <div>
     <div>
-      <%= link_to h(comic.title), :controller => 'stories', :action => :show, :id => comic.id %>
+      <%= link_to h(comic.title), :controller => 'stories', :action => :comic, :id => comic.id %>
     </div>
     <div>
       作家:<%= h comic.author.name %>
     </div>
     <div>
       作家:<%= h comic.author.name %>
index ff14561..45a8b70 100644 (file)
  <p class="notice"><%= notice %></p>\r
  <p class="alert"><%= alert %></p>\r
 <%= link_to 'comics', main_app.comics_path %>\r
  <p class="notice"><%= notice %></p>\r
  <p class="alert"><%= alert %></p>\r
 <%= link_to 'comics', main_app.comics_path %>\r
+<%= link_to 'stories', main_app.stories_path %>\r
 <%= link_to 'panels', main_app.panels_path %>\r
 <%= link_to 'original_pictures', main_app.original_pictures_path %>\r
 <%= link_to 'resource_pictures', main_app.resource_pictures_path %>\r
 <%= link_to 'panel_pictures', main_app.panel_pictures_path %>\r
 <%= link_to 'panels', main_app.panels_path %>\r
 <%= link_to 'original_pictures', main_app.original_pictures_path %>\r
 <%= link_to 'resource_pictures', main_app.resource_pictures_path %>\r
 <%= link_to 'panel_pictures', main_app.panel_pictures_path %>\r
-<%= link_to 'speech_balloons', main_app.speech_balloons_path %>\r
-<%= link_to 'balloons', main_app.balloons_path %>\r
-<%= link_to 'speeches', main_app.speeches_path %>\r
  : \r
 <%= link_to 'speech_balloon_templates', main_app.speech_balloon_templates_path %>\r
 <%= link_to 'colors', main_app.colors_path %>\r
  : \r
 <%= link_to 'speech_balloon_templates', main_app.speech_balloon_templates_path %>\r
 <%= link_to 'colors', main_app.colors_path %>\r
index 3ea04e5..148dee0 100644 (file)
@@ -1,26 +1,12 @@
-<h1>Listing speech_balloons</h1>
+<h1>Listing speach balloon template</h1>
 <table>
   <tr>
     <th>Name</th>
 <table>
   <tr>
     <th>Name</th>
-    <th>Tail count</th>
-    <th>size count</th>
-    <th>t</th>
-    <th></th>
-    <th></th>
   </tr>
 
   </tr>
 
-<% @speech_balloons.each do |speech_balloon| %>
+<% @speech_balloon_templates.each do |st| %>
   <tr>
   <tr>
-    <td><%= h speech_balloon.name %></td>
-    <td><%= speech_balloon.tail_count %></td>
-    <td><%= speech_balloon.size_count %></td>
-    <td><%= speech_balloon.t %></td>
-    <td><%= link_to 'show', speech_balloon %></td>
-    <td>
-      <% if admin_signed_in? -%>
-        <%= link_to 'Destroy', speech_balloon, confirm: 'Are you sure?', method: :delete %>
-      <% end -%>
-    </td>
+    <td><%= h st.caption %></td>
   </tr>
 <% end %>
 </table>
   </tr>
 <% end %>
 </table>
diff --git a/app/views/stories/comic.html.erb b/app/views/stories/comic.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 dfa9eff..c8b19a8 100644 (file)
@@ -1,16 +1,12 @@
-<h1><%= h @comic.title %></h1>
-
-<% @stories.each do |story| %>
-  <% @story = story %>
   <% @panel = story.panel %>
   <%= render 'panels/standard' %>
   <% @panel = story.panel %>
   <%= render 'panels/standard' %>
-  <% if story.author.id == @author.id -%>
+  <% if @story.author.id == @author.id -%>
     <span>
     <span>
-    t:<%= story.t %>
+    t:<%= @story.t %>
     </span>
 <%= button_to 'Destroy', @story, confirm: 'Are you sure?', method: :delete %>
     <%= render 'editform' %>
     </span>
 <%= button_to 'Destroy', @story, confirm: 'Are you sure?', method: :delete %>
     <%= render 'editform' %>
-    <%= link_to 'open js', edit_story_path(story), :remote => true %>
+    <%= link_to 'open js', edit_story_path(@story), :remote => true %>
       <div id="story-update-<%= @story.id -%>">
         t
       </div>
       <div id="story-update-<%= @story.id -%>">
         t
       </div>
@@ -21,5 +17,3 @@
     <div id="story-create">
       t
     </div>
     <div id="story-create">
       t
     </div>
-<% end %>
-<%= link_to 'Back', comics_path %>
index 6a1e38c..f984d8e 100644 (file)
@@ -243,6 +243,7 @@ Pettanr::Application.routes.draw do
   # Keep in mind you can assign values other than :controller and :action
   match 'resource_pictures/:subdir/:id(.:format)/' => 'resource_pictures#show'
   match 'pictures/:subdir/:id(.:format)/' => 'pictures#show'
   # Keep in mind you can assign values other than :controller and :action
   match 'resource_pictures/:subdir/:id(.:format)/' => 'resource_pictures#show'
   match 'pictures/:subdir/:id(.:format)/' => 'pictures#show'
+  match 'stories/comic/:id(.:format)' => 'stories#comic'
   match 'home/(:action)', :controller => 'home'
   match 'system/(:action)', :controller => 'system'
   match 'authors/(:action(/:id))', :controller => 'authors'
   match 'home/(:action)', :controller => 'home'
   match 'system/(:action)', :controller => 'system'
   match 'authors/(:action(/:id))', :controller => 'authors'
index c780055..4f67cbd 100644 (file)
@@ -5,5 +5,5 @@
     "height": 200,\r
     "visible": 3\r
   },\r
     "height": 200,\r
     "visible": 3\r
   },\r
-  "auth_token": "vX7rc33zxVJSQPKjp2vc"\r
+  "auth_token": "3fhobSVvDxjUSUPSKy5y"\r
 }
\ No newline at end of file
 }
\ No newline at end of file
index 6020ade..5b49435 100644 (file)
@@ -2,5 +2,5 @@
   "original_picture": {\r
     "file": \r
 "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"  },\r
   "original_picture": {\r
     "file": \r
 "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"  },\r
-  "auth_token": "vX7rc33zxVJSQPKjp2vc"\r
+  "auth_token": "3fhobSVvDxjUSUPSKy5y"\r
 }
\ No newline at end of file
 }
\ No newline at end of file
index 5301454..a9d642c 100644 (file)
@@ -37,5 +37,5 @@
       }\r
     }\r
   },\r
       }\r
     }\r
   },\r
-  "auth_token": "3d3Fvz9RafTPcpzLrYSW"\r
+  "auth_token": "3fhobSVvDxjUSUPSKy5y"\r
 }
\ No newline at end of file
 }
\ No newline at end of file
index 75d07d2..6ccc5f2 100644 (file)
@@ -3,5 +3,5 @@
     "comic_id": 1,\r
     "panel_id": 1\r
   },\r
     "comic_id": 1,\r
     "panel_id": 1\r
   },\r
-  "auth_token": "vX7rc33zxVJSQPKjp2vc"\r
+  "auth_token": "3fhobSVvDxjUSUPSKy5y"\r
 }
\ No newline at end of file
 }
\ No newline at end of file
index 2809d26..f42e53f 100644 (file)
@@ -174,10 +174,6 @@ describe HomeController do
           get :panel, :format => :json
           lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
         end
           get :panel, :format => :json
           lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
         end
-        it 'コマモデルにjson一覧出力オプションを問い合わせている' do
-          Panel.should_receive(:list_json_opt).exactly(1)
-          get :panel, :format => :json
-        end
         it 'データがリスト構造になっている' do
           get :panel, :format => :json
           json = JSON.parse response.body
         it 'データがリスト構造になっている' do
           get :panel, :format => :json
           json = JSON.parse response.body
index db00bf2..31e8bfc 100644 (file)
@@ -44,10 +44,6 @@ describe PanelsController do
       end\r
     end\r
     context 'つつがなく終わるとき' do\r
       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
         Panel.should_receive(:list).exactly(1)\r
         get :index\r
       it 'コマモデルに一覧を問い合わせている' do\r
         Panel.should_receive(:list).exactly(1)\r
         get :index\r
@@ -57,18 +53,26 @@ describe PanelsController do
         assigns(:panels).should have_at_least(3).items\r
       end\r
       context 'html形式' do\r
         assigns(:panels).should have_at_least(3).items\r
       end\r
       context 'html形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          get :index\r
+          response.should be_success \r
+        end\r
         it 'indexテンプレートを描画する' do\r
           get :index\r
           response.should render_template("index")\r
         end\r
       end\r
       context 'json形式' do\r
         it 'indexテンプレートを描画する' do\r
           get :index\r
           response.should render_template("index")\r
         end\r
       end\r
       context 'json形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          get :index, :format => :json\r
+          response.should be_success \r
+        end\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 'jsonデータを返す' do\r
           get :index, :format => :json\r
           lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
         end\r
-        it 'コマモデルにjson一覧出力オプションを問い合わせている' do
-          Panel.should_receive(:list_json_opt).exactly(1)
+        it 'コマモデルにコマのjson出力を問い合わせている' do
+          Panel.any_instance.should_receive(:panel_elements_as_json).exactly(3)
           get :index, :format => :json
         end
         it 'データがリスト構造になっている' do\r
           get :index, :format => :json
         end
         it 'データがリスト構造になっている' do\r
@@ -113,14 +117,10 @@ describe PanelsController do
   describe '単体表示に於いて' do\r
     before do\r
       @panel = FactoryGirl.create :panel, :author_id => @user.author.id\r
   describe '単体表示に於いて' do\r
     before do\r
       @panel = FactoryGirl.create :panel, :author_id => @user.author.id\r
-      Panel.stub(:show).and_return(@panel)\r
+      Panel.stub(:show).with(@panel.id.to_s, @author).and_return(@panel)\r
       sign_in @user\r
     end\r
     context 'つつがなく終わるとき' do\r
       sign_in @user\r
     end\r
     context 'つつがなく終わるとき' do\r
-      it 'ステータスコード200 OKを返す' do\r
-        get :show, :id => @panel.id\r
-        response.should be_success\r
-      end\r
       it 'コマモデルに単体取得を問い合わせている' do\r
         Panel.should_receive(:show).exactly(1)\r
         get :show\r
       it 'コマモデルに単体取得を問い合わせている' do\r
         Panel.should_receive(:show).exactly(1)\r
         get :show\r
@@ -130,16 +130,28 @@ describe PanelsController do
         assigns(:panel).id.should eq(@panel.id)\r
       end\r
       context 'html形式' do\r
         assigns(:panel).id.should eq(@panel.id)\r
       end\r
       context 'html形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          get :show, :id => @panel.id\r
+          response.should be_success\r
+        end\r
         it 'showテンプレートを描画する' do\r
           get :show, :id => @panel.id\r
           response.should render_template("show")\r
         end\r
       end\r
       context 'json形式' do\r
         it 'showテンプレートを描画する' do\r
           get :show, :id => @panel.id\r
           response.should render_template("show")\r
         end\r
       end\r
       context 'json形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          get :show, :id => @panel.id, :format => :json\r
+          response.should be_success\r
+        end\r
         it 'jsonデータを返す' do\r
           get :show, :id => @panel.id, :format => :json\r
           lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
         end\r
         it 'jsonデータを返す' do\r
           get :show, :id => @panel.id, :format => :json\r
           lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
         end\r
+        it 'コマモデルにコマのjson出力を問い合わせている' do
+          Panel.any_instance.should_receive(:panel_elements_as_json).exactly(1)
+          get :show, :id => @panel.id, :format => :json
+        end
         it 'データがアレになっている' do\r
           get :show, :id => @panel.id, :format => :json\r
           json = JSON.parse response.body\r
         it 'データがアレになっている' do\r
           get :show, :id => @panel.id, :format => :json\r
           json = JSON.parse response.body\r
@@ -241,10 +253,6 @@ describe PanelsController do
       sign_in @user\r
     end\r
     context 'つつがなく終わるとき' 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 '@panelに新規データを用意している' do\r
         get :new\r
         assigns(:panel).should be_a_new(Panel)\r
       it '@panelに新規データを用意している' do\r
         get :new\r
         assigns(:panel).should be_a_new(Panel)\r
@@ -254,6 +262,10 @@ describe PanelsController do
         get :new\r
       end\r
       context 'html形式' do\r
         get :new\r
       end\r
       context 'html形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          get :new\r
+          response.should be_success \r
+        end\r
         it 'newテンプレートを描画する' do\r
           get :new\r
           response.should render_template("new")\r
         it 'newテンプレートを描画する' do\r
           get :new\r
           response.should render_template("new")\r
@@ -265,6 +277,16 @@ describe PanelsController do
           response.should render_template("new")\r
         end\r
       end\r
           response.should render_template("new")\r
         end\r
       end\r
+      context 'json形式' do
+        it 'jsonデータを返す' do
+          get :new, :format => :json
+          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+        end
+        it 'コマモデルにコマのjson出力を問い合わせている' do
+          Panel.any_instance.should_receive(:panel_elements_as_json).exactly(1)
+          get :new, :format => :json
+        end
+      end
     end\r
     context '作家権限がないとき' do\r
       before do\r
     end\r
     context '作家権限がないとき' do\r
       before do\r
@@ -295,13 +317,12 @@ describe PanelsController do
   \r
   describe '新規作成に於いて' do\r
     before do\r
   \r
   describe '新規作成に於いて' do\r
     before do\r
-      @panel = FactoryGirl.create :panel, :author_id => @user.author.id\r
+      @panel = FactoryGirl.build :panel, :author_id => @author.id\r
       @attr = FactoryGirl.attributes_for(:panel, :author_id => @author.id)\r
       sign_in @user\r
     end\r
     context '事前チェックする' do\r
       before do\r
       @attr = FactoryGirl.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
         Panel.stub(:count).and_return(10)\r
       end\r
       it 'panelがパラメータにあれば、展開する' do\r
@@ -319,20 +340,16 @@ describe PanelsController do
         }\r
         assigns(:prm)['border'].to_i.should eq @panel.border\r
       end\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(: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 => @attr\r
       end\r
       it 'モデルに保存依頼する' do\r
         Panel.any_instance.should_receive(:store).exactly(1)\r
         post :create, :panel => @attr\r
       end\r
+    end\r
+    context 'つつがなく終わるとき' do\r
       it "@panelに作成されたコマを保持していて、それがDBにある" do\r
         post :create, :panel => @attr\r
         assigns(:panel).should be_a(Panel)\r
       it "@panelに作成されたコマを保持していて、それがDBにある" do\r
         post :create, :panel => @attr\r
         assigns(:panel).should be_a(Panel)\r
@@ -360,6 +377,10 @@ describe PanelsController do
           post :create, :panel => @attr, :format => :json\r
           lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
         end\r
           post :create, :panel => @attr, :format => :json\r
           lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
         end\r
+        it 'コマモデルにコマのjson出力を問い合わせている' do
+          Panel.any_instance.should_receive(:panel_elements_as_json).exactly(1)
+          post :create, :panel => @attr, :format => :json\r
+        end
         it 'データがアレになっている' do\r
           post :create, :panel => @attr, :format => :json\r
           json = JSON.parse response.body\r
         it 'データがアレになっている' do\r
           post :create, :panel => @attr, :format => :json\r
           json = JSON.parse response.body\r
@@ -430,10 +451,6 @@ describe PanelsController do
       Panel.stub(:show).and_return(@panel)\r
     end\r
     context 'つつがなく終わるとき' do\r
       Panel.stub(:show).and_return(@panel)\r
     end\r
     context 'つつがなく終わるとき' do\r
-      it 'ステータスコード200 OKを返す' do\r
-        get :edit, :id => @panel.id\r
-        response.should be_success \r
-      end\r
       it 'コマモデルに編集取得を問い合わせている' do\r
         Panel.should_receive(:edit).exactly(1)\r
         get :edit, :id => @panel.id\r
       it 'コマモデルに編集取得を問い合わせている' do\r
         Panel.should_receive(:edit).exactly(1)\r
         get :edit, :id => @panel.id\r
@@ -443,12 +460,20 @@ describe PanelsController do
         assigns(:panel).should eq @panel\r
       end\r
       context 'html形式' do\r
         assigns(:panel).should eq @panel\r
       end\r
       context 'html形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          get :edit, :id => @panel.id\r
+          response.should be_success \r
+        end\r
         it 'editテンプレートを描画する' do\r
           get :edit, :id => @panel.id\r
           response.should render_template("edit")\r
         end\r
       end\r
       context 'js形式' do\r
         it 'editテンプレートを描画する' do\r
           get :edit, :id => @panel.id\r
           response.should render_template("edit")\r
         end\r
       end\r
       context 'js形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          get :edit, :id => @panel.id, :format => :js\r
+          response.should be_success \r
+        end\r
         it 'edit.jsテンプレートを描画する' do\r
           get :edit, :id => @panel.id, :format => :js\r
           response.should render_template("edit")\r
         it 'edit.jsテンプレートを描画する' do\r
           get :edit, :id => @panel.id, :format => :js\r
           response.should render_template("edit")\r
@@ -516,10 +541,6 @@ describe PanelsController do
         Panel.should_receive(:edit).exactly(1)\r
         put :update, :id => @panel.id, :panel => @attr\r
       end\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
       it 'モデルに保存依頼する' do\r
         Panel.any_instance.should_receive(:store).exactly(1)\r
         put :update, :id => @panel.id, :panel => @attr\r
@@ -547,6 +568,11 @@ describe PanelsController do
           put :update, :id => @panel.id, :panel => @attr, :format => :json\r
           response.should be_success \r
         end\r
           put :update, :id => @panel.id, :panel => @attr, :format => :json\r
           response.should be_success \r
         end\r
+        it 'ページ本体は特に返さない' do\r
+          Panel.any_instance.stub(:save).with(any_args()).and_return(true)\r
+          put :update, :id => @panel.id, :panel => @attr, :format => :json\r
+          response.body.should match /./\r
+        end\r
       end\r
     end\r
     context '作家権限がないとき' do\r
       end\r
     end\r
     context '作家権限がないとき' do\r
index 0ac61e4..ec5310d 100644 (file)
@@ -13,18 +13,194 @@ describe StoriesController do
     @panel = FactoryGirl.create :panel, :author_id => @author.id
   end
   
     @panel = FactoryGirl.create :panel, :author_id => @author.id
   end
   
-
+  describe '一覧表示に於いて' do
+  end
+  
+  describe '単体表示に於いて' do
+    before do
+      sign_in @user
+      @story = FactoryGirl.create :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+      Comic.stub(:show).with(@comic.id.to_s, @author).and_return(@comic)
+      Story.stub(:show).with(@story.id.to_s, @author).and_return(@story)
+    end
+    context 'つつがなく終わるとき' do
+      it 'ストーリーモデルに単体取得を問い合わせている' do
+        Story.should_receive(:show).with(@story.id.to_s, @author).exactly(1)
+        get :show, :id => @story.id
+      end
+      it '@storyにアレを取得している' do
+        get :show, :id => @story.id
+        assigns(:story).should eq @story
+      end
+      context 'html形式' do
+        it 'ステータスコード200 OKを返す' do
+          get :show, :id => @story.id
+          response.should be_success
+        end
+        it 'showテンプレートを描画する' do
+          get :show, :id => @story.id
+          response.should render_template("show")
+        end
+      end
+      context 'json形式' do
+        it 'ステータスコード200 OKを返す' do
+          get :show, :id => @story.id, :format => :json
+          response.should be_success
+        end
+        it 'jsonデータを返す' do
+          get :show, :id => @story.id, :format => :json
+          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+        end
+        it 'ストーリーモデルにストーリーjson出力を問い合わせている' do
+          Story.any_instance.should_receive(:story_as_json).exactly(1)
+          get :show, :id => @story.id, :format => :json
+        end
+        it 'データがアレになっている' do
+          get :show, :id => @story.id, :format => :json
+          json = JSON.parse response.body
+          json.has_key?("panel_id").should be_true\r
+          json.has_key?("comic_id").should be_true\r
+          json.has_key?("author_id").should be_true\r
+        end
+      end
+    end
+    context '作家権限がないとき' do
+      before do
+        sign_out @user
+      end
+      context 'html形式' do
+        it 'ステータスコード302 Foundを返す' do
+          get :show, :id => @story.id
+          response.status.should eq 302
+        end
+        it 'サインインページへ遷移する' do
+          get :show, :id => @story.id
+          response.body.should redirect_to '/users/sign_in'
+        end
+      end
+      context 'json形式' do
+        it 'ステータスコード401 Unauthorizedを返す' do
+          get :show, :id => @story.id, :format => :json
+          response.status.should eq 401
+        end
+        it '応答メッセージにUnauthorizedを返す' do
+          get :show, :id => @story.id, :format => :json
+          response.message.should match(/Unauthorized/)
+        end
+      end
+    end
+  end
+  
   describe '閲覧に於いて' do
     before do
       @story = FactoryGirl.create :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
   describe '閲覧に於いて' do
     before do
       @story = FactoryGirl.create :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
-      Comic.stub(:show).and_return(@comic)
+      Comic.stub(:show).with(@comic.id.to_s, @author).and_return(@comic)
+      Story.stub(:count).and_return(10)
+      Story.stub(:play_list).with(any_args).and_return([@story, @story, @story])\r
       sign_in @user
     end
       sign_in @user
     end
+    context 'パラメータチェックする' do
+      it '与えられたoffsetがセットされている' do\r
+        get :comic, :id => @comic.id, :offset => 5\r
+        assigns(:offset).should eq 5\r
+      end\r
+      it '省略されると@offsetに0値が入る' do\r
+        get :comic, :id => @comic.id\r
+        assigns(:offset).should eq 0\r
+      end\r
+      it '与えられたcountがセットされている' do\r
+        get :comic, :id => @comic.id, :count => 4\r
+        assigns(:panel_count).should eq 4\r
+      end\r
+      it '省略されると@panel_countにデフォルト値が入る' do\r
+        get :comic, :id => @comic.id\r
+        assigns(:panel_count).should eq Story.default_panel_size\r
+      end\r
+      it '最大を超えると@panel_countにデフォルト最大値が入る' do\r
+        get :comic, :id => @comic.id, :count => 1500\r
+        assigns(:panel_count).should eq Story.max_panel_size\r
+      end\r
+      it '不正な値が入ると@panel_countにデフォルト最大値が入る' do\r
+        get :comic, :id => @comic.id, :count => -1\r
+        assigns(:panel_count).should eq Story.default_panel_size\r
+      end\r
+    end
     context '事前チェックする' do
     context '事前チェックする' do
+      it 'コミックモデルに単体取得を問い合わせている' do\r
+        Comic.should_receive(:show).with(@comic.id.to_s, @author).exactly(1)\r
+        get :comic, :id => @comic.id\r
+      end\r
+      it 'ストーリーモデルにプレイリスト取得を問い合わせている' do\r
+        Story.should_receive(:play_list).with(@comic, @author, 0, 30).exactly(1)\r
+        get :comic, :id => @comic.id\r
+      end\r
     end
     context 'つつがなく終わるとき' do
     end
     context 'つつがなく終わるとき' do
+      it '@storiesにリストを取得している' do\r
+        get :comic, :id => @comic.id\r
+        assigns(:stories).should have_at_least(3).items\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          get :comic, :id => @comic.id\r
+          response.should be_success \r
+        end\r
+        it 'comicテンプレートを描画する' do\r
+          get :comic, :id => @comic.id\r
+          response.should render_template("comic")\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード200 OKを返す' do\r
+          get :comic, :id => @comic.id, :format => :json\r
+          response.should be_success \r
+        end\r
+        it 'jsonデータを返す' do\r
+          get :comic, :id => @comic.id, :format => :json\r
+          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
+        end\r
+        it 'ストーリーモデルのストーリーのjson出力を問い合わせている' do
+          Story.any_instance.should_receive(:story_as_json).exactly(3)
+          get :comic, :id => @comic.id, :format => :json\r
+        end
+        it 'データがリスト構造になっている' do\r
+          get :comic, :id => @comic.id, :format => :json\r
+          json = JSON.parse response.body\r
+          json.should have_at_least(3).items\r
+        end\r
+        it 'リストの先頭くらいはストーリーっぽいものであって欲しい' do\r
+          get :comic, :id => @comic.id, :format => :json\r
+          json = JSON.parse response.body\r
+          json.first.has_key?("panel_id").should be_true\r
+          json.first.has_key?("comic_id").should be_true\r
+          json.first.has_key?("author_id").should be_true\r
+        end\r
+      end\r
     end
     context '作家権限がないとき' do
     end
     context '作家権限がないとき' do
+      before do\r
+        sign_out @user\r
+      end\r
+      context 'html形式' do\r
+        it 'ステータスコード302 Foundを返す' do\r
+          get :comic, :id => @comic.id\r
+          response.status.should eq 302\r
+        end\r
+        it 'サインインページへ遷移する' do\r
+          get :comic, :id => @comic.id\r
+          response.should redirect_to '/users/sign_in'\r
+        end\r
+      end\r
+      context 'json形式' do\r
+        it 'ステータスコード401 Unauthorizedを返す' do\r
+          get :comic, :id => @comic.id, :format => :json\r
+          response.status.should eq 401\r
+        end\r
+        it '応答メッセージにUnauthorizedを返す' do\r
+          get :comic, :id => @comic.id, :format => :json\r
+          response.message.should match(/Unauthorized/)\r
+        end\r
+      end\r
     end
   end
 
     end
   end
 
@@ -33,10 +209,6 @@ describe StoriesController do
       sign_in @user
     end
     context 'つつがなく終わるとき' 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)
       it '@storyに新規データを用意している' do
         get :new
         assigns(:story).should be_a_new(Story)
@@ -46,17 +218,46 @@ describe StoriesController do
         get :new
       end
       context 'html形式' do
         get :new
       end
       context 'html形式' do
+        it 'ステータスコード200 OKを返す' do
+          get :new
+          response.should be_success 
+        end
         it 'newテンプレートを描画する' do
           get :new
           response.should render_template("new")
         end
       end
       context 'js形式' do
         it 'newテンプレートを描画する' do
           get :new
           response.should render_template("new")
         end
       end
       context 'js形式' do
+        it 'ステータスコード200 OKを返す' do
+          get :new, :format => :js
+          response.should be_success 
+        end
         it 'new.jsテンプレートを描画する' do
           get :new, :format => :js
           response.should render_template("new")
         end
       end
         it 'new.jsテンプレートを描画する' do
           get :new, :format => :js
           response.should render_template("new")
         end
       end
+      context 'json形式' do
+        it 'ステータスコード200 OKを返す' do
+          get :new, :format => :json
+          response.should be_success 
+        end
+        it 'jsonデータを返す' do\r
+          get :new, :format => :json
+          lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)\r
+        end\r
+        it 'ストーリーモデルのストーリーのjson出力を問い合わせている' do
+          Story.any_instance.should_receive(:story_as_json).exactly(1)
+          get :new, :format => :json
+        end
+        it 'データがアレになっている' do
+          get :new, :format => :json
+          json = JSON.parse response.body
+          json.has_key?("panel_id").should be_true\r
+          json.has_key?("comic_id").should be_true\r
+          json.has_key?("author_id").should be_true\r
+        end
+      end
     end
     context '作家権限がないとき' do
       before do
     end
     context '作家権限がないとき' do
       before do
@@ -72,13 +273,13 @@ describe StoriesController do
           response.body.should redirect_to '/users/sign_in'
         end
       end
           response.body.should redirect_to '/users/sign_in'
         end
       end
-      context 'js形式' do
+      context 'json形式' do
         it 'ステータスコード401 Unauthorizedを返す' do
         it 'ステータスコード401 Unauthorizedを返す' do
-          get :new, :format => :js
+          get :new, :format => :json
           response.status.should eq 401
         end
         it '応答メッセージにUnauthorizedを返す' do
           response.status.should eq 401
         end
         it '応答メッセージにUnauthorizedを返す' do
-          get :new, :format => :js
+          get :new, :format => :json
           response.message.should match(/Unauthorized/)
         end
       end
           response.message.should match(/Unauthorized/)
         end
       end
@@ -97,13 +298,22 @@ describe StoriesController do
       end
       it 'POSTデータから、カラム値を復元している' do
         Story.any_instance.stub(:store).and_return(true)
       end
       it 'POSTデータから、カラム値を復元している' do
         Story.any_instance.stub(:store).and_return(true)
-        Story.any_instance.should_receive(:attributes=).exactly(1)
         post :create, :story => @attr
         post :create, :story => @attr
+        assigns(:story).comic_id.should eq @comic.id
+        assigns(:story).panel_id.should eq @panel.id
       end
       it '上書き補充を依頼する' do
         Story.any_instance.should_receive(:overwrite).exactly(1)
         post :create, :story => @attr
       end
       end
       it '上書き補充を依頼する' do
         Story.any_instance.should_receive(:overwrite).exactly(1)
         post :create, :story => @attr
       end
+      it 'コミックモデルに編集取得を依頼している' do
+        Comic.should_receive(:edit).with(@comic.id, @author).exactly(1)
+        post :create, :story => @attr
+      end
+      it 'コマモデルに単体取得を依頼している' do
+        Panel.should_receive(:show).with(@panel.id, @author).exactly(1)
+        post :create, :story => @attr
+      end
       it 'モデルに保存依頼する' do
         Story.any_instance.should_receive(:store).exactly(1)
         post :create, :story => @attr
       it 'モデルに保存依頼する' do
         Story.any_instance.should_receive(:store).exactly(1)
         post :create, :story => @attr
@@ -122,7 +332,7 @@ describe StoriesController do
         it 'コミックのストーリー表示へ遷移する' do
 #          Story.any_instance.stub(:store).and_return(true)
           post :create, :story => @attr
         it 'コミックのストーリー表示へ遷移する' do
 #          Story.any_instance.stub(:store).and_return(true)
           post :create, :story => @attr
-          response.should redirect_to(:action => :show, :id => @attr[:comic_id])
+          response.should redirect_to(:action => :comic, :id => @attr[:comic_id])
         end
       end
       context 'json形式' do
         end
       end
       context 'json形式' do
@@ -135,6 +345,10 @@ describe StoriesController do
           post :create, :story => @attr, :format => :json
           lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
         end
           post :create, :story => @attr, :format => :json
           lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
         end
+        it 'ストーリーモデルのストーリーのjson出力を問い合わせている' do
+          Story.any_instance.should_receive(:story_as_json).exactly(1)
+          post :create, :story => @attr, :format => :json
+        end
         it 'データがアレになっている' do
           post :create, :story => @attr, :format => :json
           json = JSON.parse response.body
         it 'データがアレになっている' do
           post :create, :story => @attr, :format => :json
           json = JSON.parse response.body
@@ -205,11 +419,7 @@ describe StoriesController do
       Story.stub(:show).and_return(@story)
     end
     context 'つつがなく終わるとき' do
       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
+      it 'ストーリーモデルに編集取得を問い合わせている' do
         Story.should_receive(:edit).exactly(1)
         get :edit, :id => @story.id
       end
         Story.should_receive(:edit).exactly(1)
         get :edit, :id => @story.id
       end
@@ -218,12 +428,20 @@ describe StoriesController do
         assigns(:story).should eq @story
       end
       context 'html形式' do
         assigns(:story).should eq @story
       end
       context 'html形式' do
+        it 'ステータスコード200 OKを返す' do
+          get :edit, :id => @story.id
+          response.should be_success 
+        end
         it 'editテンプレートを描画する' do
           get :edit, :id => @story.id
           response.should render_template("edit")
         end
       end
       context 'js形式' do
         it 'editテンプレートを描画する' do
           get :edit, :id => @story.id
           response.should render_template("edit")
         end
       end
       context 'js形式' do
+        it 'ステータスコード200 OKを返す' do
+          get :edit, :id => @story.id, :format => :js
+          response.should be_success 
+        end
         it 'edit.jsテンプレートを描画する' do
           get :edit, :id => @story.id, :format => :js
           response.should render_template("edit")
         it 'edit.jsテンプレートを描画する' do
           get :edit, :id => @story.id, :format => :js
           response.should render_template("edit")
@@ -293,10 +511,10 @@ describe StoriesController do
           put :update, :id => @story.id, :story => @attr
           response.status.should eq 302
         end
           put :update, :id => @story.id, :story => @attr
           response.status.should eq 302
         end
-        it 'ã\82³ã\83\9fã\83\83ã\82¯ã\81®ã\82¹ã\83\88ã\83¼ã\83ªã\83¼è¡¨ç¤ºã\81¸é\81·ç§»ã\81\99ã\82\8b' do
+        it 'ストーリー表示へ遷移する' do
 #          Story.any_instance.stub(:store).and_return(true)
           put :update, :id => @story.id, :story => @attr
 #          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])
+          response.should redirect_to(:action => :comic, :id => @attr[:comic_id])
         end
       end
       context 'json形式' do
         end
       end
       context 'json形式' do
index 8887e3e..f83e83f 100644 (file)
@@ -318,7 +318,7 @@ describe Comic do
         @comic3 = FactoryGirl.create :comic, :author_id => @author.id, :updated_at => Time.now + 200
         @comic4 = FactoryGirl.create :comic, :author_id => @author.id, :updated_at => Time.now + 300
         @comic5 = FactoryGirl.create :comic, :author_id => @author.id, :updated_at => Time.now + 400
         @comic3 = FactoryGirl.create :comic, :author_id => @author.id, :updated_at => Time.now + 200
         @comic4 = FactoryGirl.create :comic, :author_id => @author.id, :updated_at => Time.now + 300
         @comic5 = FactoryGirl.create :comic, :author_id => @author.id, :updated_at => Time.now + 400
-        Color.stub(:default_page_size).and_return(0)
+        Comic.stub(:default_page_size).and_return(2)
       end
       it '通常は全件(5件)を返す' do
         r = Comic.mylist @author, 5, 0
       end
       it '通常は全件(5件)を返す' do
         r = Comic.mylist @author, 5, 0
index a85ed4b..bed7168 100644 (file)
@@ -485,7 +485,7 @@ describe PanelPicture do
     it '自分のコマのコマ絵は非公開コマでも含んでいる' do
       pl = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0
       ni = FactoryGirl.create :panel_picture, :panel_id => pl.id, :picture_id => @p.id,
     it '自分のコマのコマ絵は非公開コマでも含んでいる' do
       pl = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0
       ni = FactoryGirl.create :panel_picture, :panel_id => pl.id, :picture_id => @p.id,
-        :width => @p.width, :height => @p.height
+        :width => @p.width, :height => @p.height, :updated_at => Time.now + 100
       r = PanelPicture.mylist @author
       r.should eq [ni, @pp]
     end
       r = PanelPicture.mylist @author
       r.should eq [ni, @pp]
     end
index ecf150a..002f9dd 100644 (file)
@@ -7,6 +7,7 @@ describe Panel do
     @sp = FactoryGirl.create :system_picture\r
     @lg = FactoryGirl.create :license_group\r
     @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id\r
     @sp = FactoryGirl.create :system_picture\r
     @lg = FactoryGirl.create :license_group\r
     @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id\r
+    @color = FactoryGirl.create :color
     @user = FactoryGirl.create( :user_yas)\r
     @author = @user.author\r
     @artist = FactoryGirl.create :artist_yas, :author_id => @author.id\r
     @user = FactoryGirl.create( :user_yas)\r
     @author = @user.author\r
     @artist = FactoryGirl.create :artist_yas, :author_id => @author.id\r
@@ -21,21 +22,33 @@ describe Panel do
   \r
   describe '検証に於いて' do\r
     before do\r
   \r
   describe '検証に於いて' do\r
     before do\r
-    end\r
-    \r
-    it 'オーソドックスなデータなら通る' do\r
       @panel = FactoryGirl.build :panel, :author_id => @author.id\r
       @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-      @panel.should be_valid\r
     end\r
     \r
     end\r
     \r
+    context 'オーソドックスなデータのとき' do
+      it '下限データが通る' do
+        @panel.width = 1
+        @panel.height = 1
+        @panel.border = 0
+        @panel.x = -99999
+        @panel.y = -99999
+        @panel.z = 1
+        @panel.publish = 0
+        @panel.should be_valid
+      end
+      it '上限データが通る' do
+        @panel.width = 99999
+        @panel.height = 99999
+        @panel.border = 99999
+        @panel.x = 99999
+        @panel.y = 99999
+        @panel.z = 99999
+        @panel.publish = 99999
+        @panel.should be_valid
+      end
+    end
+    
     context 'widthを検証するとき' do\r
     context 'widthを検証するとき' do\r
-      before do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-      end\r
-      it 'テストデータの確認' do\r
-        @panel.width = 1\r
-        @panel.should be_valid\r
-      end\r
       it 'nullなら失敗する' do\r
         @panel.width = nil\r
         @panel.should_not be_valid\r
       it 'nullなら失敗する' do\r
         @panel.width = nil\r
         @panel.should_not be_valid\r
@@ -54,13 +67,6 @@ describe Panel do
       end\r
     end\r
     context 'heightを検証するとき' do\r
       end\r
     end\r
     context 'heightを検証するとき' do\r
-      before do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-      end\r
-      it 'テストデータの確認' do\r
-        @panel.height = '1'\r
-        @panel.should be_valid\r
-      end\r
       it 'nullなら失敗する' do\r
         @panel.height = nil\r
         @panel.should_not be_valid\r
       it 'nullなら失敗する' do\r
         @panel.height = nil\r
         @panel.should_not be_valid\r
@@ -79,13 +85,6 @@ describe Panel do
       end\r
     end\r
     context 'borderを検証するとき' do\r
       end\r
     end\r
     context 'borderを検証するとき' do\r
-      before do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-      end\r
-      it 'テストデータの確認' do\r
-        @panel.border = '1'\r
-        @panel.should be_valid\r
-      end\r
       it 'nullなら失敗する' do\r
         @panel.border = nil\r
         @panel.should_not be_valid\r
       it 'nullなら失敗する' do\r
         @panel.border = nil\r
         @panel.should_not be_valid\r
@@ -104,13 +103,6 @@ describe Panel do
       end\r
     end\r
     context 'xを検証するとき' do\r
       end\r
     end\r
     context 'xを検証するとき' do\r
-      before do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-      end\r
-      it 'テストデータの確認' do\r
-        @panel.x = '1'\r
-        @panel.should be_valid\r
-      end\r
       it '数値でなければ失敗する' do\r
         @panel.x = 'a'\r
         @panel.should_not be_valid\r
       it '数値でなければ失敗する' do\r
         @panel.x = 'a'\r
         @panel.should_not be_valid\r
@@ -125,13 +117,6 @@ describe Panel do
       end\r
     end\r
     context 'yを検証するとき' do\r
       end\r
     end\r
     context 'yを検証するとき' do\r
-      before do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-      end\r
-      it 'テストデータの確認' do\r
-        @panel.y = '1'\r
-        @panel.should be_valid\r
-      end\r
       it '数値でなければ失敗する' do\r
         @panel.y = 'a'\r
         @panel.should_not be_valid\r
       it '数値でなければ失敗する' do\r
         @panel.y = 'a'\r
         @panel.should_not be_valid\r
@@ -146,13 +131,6 @@ describe Panel do
       end\r
     end\r
     context 'zを検証するとき' do\r
       end\r
     end\r
     context 'zを検証するとき' do\r
-      before do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-      end\r
-      it 'テストデータの確認' do\r
-        @panel.z = '1'\r
-        @panel.should be_valid\r
-      end\r
       it '数値でなければ失敗する' do\r
         @panel.z = 'a'\r
         @panel.should_not be_valid\r
       it '数値でなければ失敗する' do\r
         @panel.z = 'a'\r
         @panel.should_not be_valid\r
@@ -167,13 +145,6 @@ describe Panel do
       end\r
     end\r
     context 'author_idを検証するとき' do\r
       end\r
     end\r
     context 'author_idを検証するとき' do\r
-      before do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-      end\r
-      it 'テストデータの確認' do\r
-        @panel.author_id = @author.id\r
-        @panel.should be_valid\r
-      end\r
       it 'nullなら失敗する' do\r
         @panel.author_id = nil\r
         @panel.should_not be_valid\r
       it 'nullなら失敗する' do\r
         @panel.author_id = nil\r
         @panel.should_not be_valid\r
@@ -182,11 +153,17 @@ describe Panel do
         @panel.author_id = 'a'\r
         @panel.should_not be_valid\r
       end\r
         @panel.author_id = 'a'\r
         @panel.should_not be_valid\r
       end\r
-      it '存在する絵師でなければ失敗する' do\r
+      it '存在する作家でなければ失敗する' do\r
         @panel.author_id = 0\r
         @panel.should_not be_valid\r
       end\r
     end\r
         @panel.author_id = 0\r
         @panel.should_not be_valid\r
       end\r
     end\r
+    context '公開フラグを検証するとき' do\r
+      it '数値でなければ失敗する' do\r
+        @panel.publish = 'a'\r
+        @panel.should_not be_valid\r
+      end\r
+    end\r
     context '全体を検証するとき' do\r
       before do\r
         @panel = FactoryGirl.create :panel, :author_id => @author.id\r
     context '全体を検証するとき' do\r
       before do\r
         @panel = FactoryGirl.create :panel, :author_id => @author.id\r
@@ -203,6 +180,11 @@ describe Panel do
       @panel.supply_default\r
       @panel.border.should eq 2\r
     end\r
       @panel.supply_default\r
       @panel.border.should eq 2\r
     end\r
+    it 'publishは0を補充する' do\r
+      @panel.publish = nil\r
+      @panel.supply_default\r
+      @panel.publish.should eq 0\r
+    end\r
   end\r
   \r
   describe '上書き補充に於いて' do\r
   end\r
   \r
   describe '上書き補充に於いて' do\r
@@ -235,6 +217,7 @@ describe Panel do
       panel.own?(nil).should == false\r
     end\r
   end\r
       panel.own?(nil).should == false\r
     end\r
   end\r
+  \r
   describe '閲覧許可に於いて' do\r
     before do\r
     end\r
   describe '閲覧許可に於いて' do\r
     before do\r
     end\r
@@ -263,192 +246,7 @@ describe Panel do
       panel.visible?(@author).should == false\r
     end\r
   end\r
       panel.visible?(@author).should == false\r
     end\r
   end\r
-  describe '単体取得に於いて' do\r
-    before do\r
-      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
-    end\r
-    it '指定のコマを返す' do\r
-      Panel.any_instance.stub(:visible?).and_return(true)\r
-      pl = Panel.show @panel.id, @author\r
-      pl.should eq @panel\r
-    end\r
-    context '他人の非公開コミックのコマを開こうとしたとき' do\r
-      it '403Forbidden例外を返す' do\r
-        Panel.any_instance.stub(:visible?).and_return(false)\r
-        lambda{\r
-          Panel.show @panel.id, @author\r
-        }.should raise_error(ActiveRecord::Forbidden)\r
-      end\r
-    end\r
-    context '存在しないコマを開こうとしたとき' do\r
-      it '404RecordNotFound例外を返す' do\r
-        lambda{\r
-          Panel.show 110, @author\r
-        }.should raise_error(ActiveRecord::RecordNotFound)\r
-      end\r
-    end\r
-  end\r
-  describe '編集取得に於いて' do\r
-    before do\r
-      @panel = FactoryGirl.create :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
-    it '6つの項目を含んでいる' do\r
-      r = Panel.show_include_opt\r
-      r.should have(6).items\r
-    end\r
-    it 'コマ絵を含んでいる' do\r
-      r = Panel.show_include_opt\r
-      r.has_key?(:panel_pictures).should be_true\r
-    end\r
-      it 'コマ絵は実素材を含んでいる' do\r
-        r = Panel.show_include_opt\r
-        r[:panel_pictures].has_key?(:picture).should be_true\r
-      end\r
-        it '実素材は絵師を含んでいる' do\r
-          r = Panel.show_include_opt\r
-          r[:panel_pictures][:picture].has_key?(:artist).should be_true\r
-        end\r
-        it '実素材はライセンスを含んでいる' do\r
-          r = Panel.show_include_opt\r
-          r[:panel_pictures][:picture].has_key?(:license).should be_true\r
-        end\r
-    it 'フキダシを含んでいる' do\r
-      r = Panel.show_include_opt\r
-      r.has_key?(:speech_balloons).should be_true\r
-    end\r
-      it 'フキダシはフキダシ枠を含んでいる' do\r
-        r = Panel.show_include_opt\r
-        r[:speech_balloons].has_key?(:balloons).should be_true\r
-      end\r
-      it 'フキダシはセリフを含んでいる' do\r
-        r = Panel.show_include_opt\r
-        r[:speech_balloons].has_key?(:speeches).should be_true\r
-      end\r
-    it '景色画像を含んでいる' do\r
-      r = Panel.show_include_opt\r
-      r.has_key?(:ground_pictures).should be_true\r
-    end\r
-      it '景色画像は実素材を含んでいる' do\r
-        r = Panel.show_include_opt\r
-        r[:ground_pictures].has_key?(:picture).should be_true\r
-      end\r
-        it '実素材は絵師を含んでいる' do\r
-          r = Panel.show_include_opt\r
-          r[:ground_pictures][:picture].has_key?(:artist).should be_true\r
-        end\r
-        it '実素材はライセンスを含んでいる' do\r
-          r = Panel.show_include_opt\r
-          r[:ground_pictures][:picture].has_key?(:license).should be_true\r
-        end\r
-    it '間接色を含んでいる' do\r
-      r = Panel.show_include_opt\r
-      r.has_key?(:ground_colors).should be_true\r
-    end\r
-      it '間接色は色を含んでいる' do\r
-        r = Panel.show_include_opt\r
-        r[:ground_colors].has_key?(:color).should be_true\r
-      end\r
-    it '景色を含んでいる' do\r
-      r = Panel.show_include_opt\r
-      r.has_key?(:panel_colors).should be_true\r
-    end\r
-    it '作家を含んでいる' do\r
-      r = Panel.show_include_opt\r
-      r.has_key?(:author).should be_true\r
-    end\r
-  end\r
-  describe 'json単体出力オプションに於いて' do\r
-    it 'includeキーを含んでいる' do\r
-      r = Panel.show_json_include_opt\r
-      r.has_key?(:include).should be_true\r
-    end\r
-    it '6つの項目を含んでいる' do\r
-      r = Panel.show_json_include_opt[:include]\r
-      r.should have(6).items\r
-    end\r
-    it 'コマ絵を含んでいる' do\r
-      r = Panel.show_json_include_opt[:include]\r
-      r.has_key?(:panel_pictures).should be_true\r
-    end\r
-      it 'コマ絵は実素材を含んでいる' do\r
-        r = Panel.show_json_include_opt[:include]\r
-        r[:panel_pictures].has_key?(:picture).should be_true\r
-      end\r
-        it '実素材は絵師を含んでいる' do\r
-          r = Panel.show_json_include_opt[:include]\r
-          r[:panel_pictures][:picture].has_key?(:artist).should be_true\r
-        end\r
-        it '実素材はライセンスを含んでいる' do\r
-          r = Panel.show_json_include_opt[:include]\r
-          r[:panel_pictures][:picture].has_key?(:license).should be_true\r
-        end\r
-    it 'フキダシを含んでいる' do\r
-      r = Panel.show_json_include_opt[:include]\r
-      r.has_key?(:speech_balloons).should be_true\r
-    end\r
-      it 'フキダシはフキダシ枠を含んでいる' do\r
-        r = Panel.show_json_include_opt[:include]\r
-        r[:speech_balloons].has_key?(:balloons).should be_true\r
-      end\r
-      it 'フキダシはセリフを含んでいる' do\r
-        r = Panel.show_json_include_opt[:include]\r
-        r[:speech_balloons].has_key?(:speeches).should be_true\r
-      end\r
-    it '景色画像を含んでいる' do\r
-      r = Panel.show_json_include_opt[:include]\r
-      r.has_key?(:ground_pictures).should be_true\r
-    end\r
-      it '景色画像は実素材を含んでいる' do\r
-        r = Panel.show_json_include_opt[:include]\r
-        r[:ground_pictures].has_key?(:picture).should be_true\r
-      end\r
-        it '実素材は絵師を含んでいる' do\r
-          r = Panel.show_json_include_opt[:include]\r
-          r[:ground_pictures][:picture].has_key?(:artist).should be_true\r
-        end\r
-        it '実素材はライセンスを含んでいる' do\r
-          r = Panel.show_json_include_opt[:include]\r
-          r[:ground_pictures][:picture].has_key?(:license).should be_true\r
-        end\r
-    it '間接色を含んでいる' do\r
-      r = Panel.show_json_include_opt[:include]\r
-      r.has_key?(:ground_colors).should be_true\r
-    end\r
-      it '間接色は色を含んでいる' do\r
-        r = Panel.show_json_include_opt[:include]\r
-        r[:ground_colors].has_key?(:color).should be_true\r
-      end\r
-    it '景色を含んでいる' do\r
-      r = Panel.show_json_include_opt[:include]\r
-      r.has_key?(:panel_colors).should be_true\r
-    end\r
-    it '作家を含んでいる' do\r
-      r = Panel.show_json_include_opt[:include]\r
-      r.has_key?(:author).should be_true\r
-    end\r
-  end\r
+  \r
   describe '一覧取得に於いて' do\r
     before do\r
       @panel = FactoryGirl.create :panel, :author_id => @author.id\r
   describe '一覧取得に於いて' do\r
     before do\r
       @panel = FactoryGirl.create :panel, :author_id => @author.id\r
@@ -479,18 +277,19 @@ describe Panel do
       end\r
     end\r
     it 'リストを返す' do\r
       end\r
     end\r
     it 'リストを返す' do\r
-      pl = Panel.list\r
-      pl.should eq [@panel]\r
+      r = Panel.list\r
+      r.should eq [@panel]\r
     end\r
     it '時系列で並んでいる' do\r
     end\r
     it '時系列で並んでいる' do\r
-      npl = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 100\r
-      pl = Panel.list\r
-      pl.should eq [npl, @panel]\r
+      #公開コミックは(他人のコミックであっても)含んでいる
+      npl = FactoryGirl.create :panel, :author_id => @other_author.id, :updated_at => Time.now + 100\r
+      r = Panel.list\r
+      r.should eq [npl, @panel]\r
     end\r
     end\r
-    it '非公開のコマは含まない' do\r
+    it '非公開のコマ(自分のコマであっても)は含まない' do\r
       npl = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0\r
       npl = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0\r
-      pl = Panel.list\r
-      pl.should eq [@panel]\r
+      r = Panel.list\r
+      r.should eq [@panel]\r
     end\r
     context 'DBに5件あって1ページの件数を2件に変えたとして' do\r
       before do\r
     end\r
     context 'DBに5件あって1ページの件数を2件に変えたとして' do\r
       before do\r
@@ -506,18 +305,31 @@ describe Panel do
       end\r
       it 'page=1なら末尾2件を返す' do\r
         #時系列で並んでいる\r
       end\r
       it 'page=1なら末尾2件を返す' do\r
         #時系列で並んでいる\r
-        pl = Panel.list( {}, 1)\r
+        pl = Panel.list 1\r
         pl.should eq [@npl5, @npl4]\r
       end\r
       it 'page=2なら中間2件を返す' do\r
         pl.should eq [@npl5, @npl4]\r
       end\r
       it 'page=2なら中間2件を返す' do\r
-        pl = Panel.list({}, 2)\r
+        pl = Panel.list 2\r
         pl.should eq [@npl3, @npl2]\r
       end\r
       it 'page=3なら先頭1件を返す' do\r
         pl.should eq [@npl3, @npl2]\r
       end\r
       it 'page=3なら先頭1件を返す' do\r
-        pl = Panel.list({}, 3)\r
+        pl = Panel.list 3\r
         pl.should eq [@panel]\r
       end\r
     end\r
         pl.should eq [@panel]\r
       end\r
     end\r
+    context 'DBに5件あって1ページの件数を2件に変えたとして' do
+      before do
+        @npl2 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 100\r
+        @npl3 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 200\r
+        @npl4 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 300\r
+        @npl5 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 400\r
+        Panel.stub(:default_page_size).and_return(2)\r
+      end
+      it '件数0は全件(5件)を返す' do
+        r = Panel.list 5, 0
+        r.should have(5).items 
+      end
+    end
   end\r
   describe 'list関連テーブルプションに於いて' do\r
     it 'includeキーを含んでいる' do\r
   end\r
   describe 'list関連テーブルプションに於いて' do\r
     it 'includeキーを含んでいる' do\r
@@ -590,120 +402,702 @@ describe Panel do
     end\r
   end\r
   describe 'json一覧出力オプションに於いて' do\r
     end\r
   end\r
   describe 'json一覧出力オプションに於いて' do\r
-    it 'includeキーを含んでいる' do\r
-      r = Panel.list_json_opt\r
-      r.has_key?(:include).should be_true\r
+  end\r
+  \r
+  describe '自分のコマ一覧取得に於いて' do\r
+    before do\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
     end\r
     end\r
-    it '6つの項目を含んでいる' do\r
-      r = Panel.list_json_opt[:include]\r
-      r.should have(6).items\r
+    it 'リストを返す' do\r
+      pl = Panel.mylist @author\r
+      pl.should eq [@panel]\r
     end\r
     end\r
-    it 'コマ絵を含んでいる' do\r
-      r = Panel.list_json_opt[:include]\r
-      r.has_key?(:panel_pictures).should be_true\r
+    it '時系列で並んでいる' do\r
+      npl = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 100\r
+      pl = Panel.mylist @author\r
+      pl.should eq [npl, @panel]\r
     end\r
     end\r
-      it 'コマ絵は実素材を含んでいる' do\r
-        r = Panel.list_json_opt[:include]\r
-        r[:panel_pictures].has_key?(:picture).should be_true\r
-      end\r
-        it '実素材は絵師を含んでいる' do\r
-          r = Panel.list_json_opt[:include]\r
-          r[:panel_pictures][:picture].has_key?(:artist).should be_true\r
-        end\r
-        it '実素材はライセンスを含んでいる' do\r
-          r = Panel.list_json_opt[:include]\r
-          r[:panel_pictures][:picture].has_key?(:license).should be_true\r
-        end\r
-    it 'フキダシを含んでいる' do\r
-      r = Panel.list_json_opt[:include]\r
-      r.has_key?(:speech_balloons).should be_true\r
+    it '他人のコマは公開でも含まない' do\r
+      npl = FactoryGirl.create :panel, :author_id => @other_author.id, :publish => 1\r
+      pl = Panel.mylist @author\r
+      pl.should eq [@panel]\r
     end\r
     end\r
-      it 'フキダシはフキダシ枠を含んでいる' do\r
-        r = Panel.list_json_opt[:include]\r
-        r[:speech_balloons].has_key?(:balloons).should be_true\r
-      end\r
-      it 'フキダシはセリフを含んでいる' do\r
-        r = Panel.list_json_opt[:include]\r
-        r[:speech_balloons].has_key?(:speeches).should be_true\r
-      end\r
-    it '景色画像を含んでいる' do\r
-      r = Panel.list_json_opt[:include]\r
-      r.has_key?(:ground_pictures).should be_true\r
+    it '自分のコマは非公開でも含んでいる' do\r
+      npl = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0, :updated_at => Time.now + 100\r
+      pl = Panel.mylist @author\r
+      pl.should eq [npl, @panel]\r
     end\r
     end\r
-      it '景色画像は実素材を含んでいる' do\r
-        r = Panel.list_json_opt[:include]\r
-        r[:ground_pictures].has_key?(:picture).should be_true\r
-      end\r
-        it '実素材は絵師を含んでいる' do\r
-          r = Panel.list_json_opt[:include]\r
-          r[:ground_pictures][:picture].has_key?(:artist).should be_true\r
+    context 'DBに5件あって1ページの件数を2件に変えたとして' do
+      before do
+        @npl2 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 100\r
+        @npl3 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 200\r
+        @npl4 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 300\r
+        @npl5 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 400\r
+      end
+      it '通常は2件を返す' do\r
+        pl = Panel.list 1, 2\r
+        pl.should have(2).items \r
+      end\r
+      it 'page=1なら末尾2件を返す' do\r
+        #時系列で並んでいる\r
+        pl = Panel.mylist @author, 1, 2\r
+        pl.should eq [@npl5, @npl4]\r
+      end\r
+      it 'page=2なら中間2件を返す' do\r
+        pl = Panel.mylist @author, 2, 2\r
+        pl.should eq [@npl3, @npl2]\r
+      end\r
+      it 'page=3なら先頭1件を返す' do\r
+        pl = Panel.mylist @author, 3, 2\r
+        pl.should eq [@panel]\r
+      end\r
+    end
+    context 'DBに5件あって1ページの件数を0件に変えたとして' do
+      before do
+        @npl2 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 100\r
+        @npl3 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 200\r
+        @npl4 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 300\r
+        @npl5 = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 400\r
+        Panel.stub(:default_page_size).and_return(2)\r
+      end
+      it '通常は全件(5件)を返す' do
+        r = Panel.mylist @author, 5, 0
+        r.should have(5).items 
+      end
+    end
+  end\r
+  \r
+  describe '単体取得に於いて' do\r
+    before do\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it '単体取得オプションを利用している' do\r
+        Panel.stub(:show_opt).with(any_args).and_return({})\r
+        Panel.should_receive(:show_opt).with(any_args).exactly(1)\r
+        r = Panel.show @panel.id, @author
+      end\r
+      it '閲覧許可を問い合わせている' do\r
+        Panel.any_instance.stub(:visible?).with(any_args).and_return(true)\r
+        Panel.any_instance.should_receive(:visible?).with(any_args).exactly(1)\r
+        r = Panel.show @panel.id, @author
+      end\r
+    end\r
+    it '指定のコマを返す' do\r
+      Panel.any_instance.stub(:visible?).and_return(true)\r
+      pl = Panel.show @panel.id, @author\r
+      pl.should eq @panel\r
+    end\r
+    context '閲覧許可が出なかったとき' do\r
+      it '403Forbidden例外を返す' do\r
+        Panel.any_instance.stub(:visible?).and_return(false)\r
+        lambda{\r
+          Panel.show @panel.id, @author\r
+        }.should raise_error(ActiveRecord::Forbidden)\r
+      end\r
+    end\r
+    context '存在しないコマを開こうとしたとき' do\r
+      it '404RecordNotFound例外を返す' do\r
+        lambda{\r
+          Panel.show 110, @author\r
+        }.should raise_error(ActiveRecord::RecordNotFound)\r
+      end\r
+    end\r
+  end\r
+  describe '編集取得に於いて' do\r
+    before do\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it '単体取得オプションを利用している' do\r
+        Panel.stub(:show_opt).with(any_args).and_return({})\r
+        Panel.should_receive(:show_opt).with(any_args).exactly(1)\r
+        r = Panel.edit @panel.id, @author
+      end\r
+      it '所持判定を問い合わせている' do\r
+        Panel.any_instance.stub(:own?).with(any_args).and_return(true)\r
+        Panel.any_instance.should_receive(:own?).with(any_args).exactly(1)\r
+        r = Panel.edit @panel.id, @author
+      end\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
+    it 'includeキーを含んでいる' do\r
+      r = Panel.show_opt\r
+      r.has_key?(:include).should be_true\r
+    end\r
+    it '6つの項目を含んでいる' do\r
+      r = Panel.show_opt[:include]\r
+      r.should have(6).items\r
+    end\r
+    it 'コマ絵を含んでいる' do\r
+      r = Panel.show_opt[:include]\r
+      r.has_key?(:panel_pictures).should be_true\r
+    end\r
+      it 'コマ絵は実素材を含んでいる' do\r
+        r = Panel.show_opt[:include]\r
+        r[:panel_pictures].has_key?(:picture).should be_true\r
+      end\r
+        it '実素材は絵師を含んでいる' do\r
+          r = Panel.show_opt[:include]\r
+          r[:panel_pictures][:picture].has_key?(:artist).should be_true\r
         end\r
         it '実素材はライセンスを含んでいる' do\r
         end\r
         it '実素材はライセンスを含んでいる' do\r
-          r = Panel.list_json_opt[:include]\r
+          r = Panel.show_opt[:include]\r
+          r[:panel_pictures][:picture].has_key?(:license).should be_true\r
+        end\r
+    it 'フキダシを含んでいる' do\r
+      r = Panel.show_opt[:include]\r
+      r.has_key?(:speech_balloons).should be_true\r
+    end\r
+      it 'フキダシはフキダシ枠を含んでいる' do\r
+        r = Panel.show_opt[:include]\r
+        r[:speech_balloons].has_key?(:balloons).should be_true\r
+      end\r
+      it 'フキダシはセリフを含んでいる' do\r
+        r = Panel.show_opt[:include]\r
+        r[:speech_balloons].has_key?(:speeches).should be_true\r
+      end\r
+    it '景色画像を含んでいる' do\r
+      r = Panel.show_opt[:include]\r
+      r.has_key?(:ground_pictures).should be_true\r
+    end\r
+      it '景色画像は実素材を含んでいる' do\r
+        r = Panel.show_opt[:include]\r
+        r[:ground_pictures].has_key?(:picture).should be_true\r
+      end\r
+        it '実素材は絵師を含んでいる' do\r
+          r = Panel.show_opt[:include]\r
+          r[:ground_pictures][:picture].has_key?(:artist).should be_true\r
+        end\r
+        it '実素材はライセンスを含んでいる' do\r
+          r = Panel.show_opt[:include]\r
           r[:ground_pictures][:picture].has_key?(:license).should be_true\r
         end\r
     it '間接色を含んでいる' do\r
           r[:ground_pictures][:picture].has_key?(:license).should be_true\r
         end\r
     it '間接色を含んでいる' do\r
-      r = Panel.list_json_opt[:include]\r
+      r = Panel.show_opt[:include]\r
       r.has_key?(:ground_colors).should be_true\r
     end\r
       it '間接色は色を含んでいる' do\r
       r.has_key?(:ground_colors).should be_true\r
     end\r
       it '間接色は色を含んでいる' do\r
-        r = Panel.list_json_opt[:include]\r
+        r = Panel.show_opt[:include]\r
         r[:ground_colors].has_key?(:color).should be_true\r
       end\r
     it '景色を含んでいる' do\r
         r[:ground_colors].has_key?(:color).should be_true\r
       end\r
     it '景色を含んでいる' do\r
-      r = Panel.list_json_opt[:include]\r
+      r = Panel.show_opt[:include]\r
       r.has_key?(:panel_colors).should be_true\r
     end\r
     it '作家を含んでいる' do\r
       r.has_key?(:panel_colors).should be_true\r
     end\r
     it '作家を含んでいる' do\r
-      r = Panel.list_json_opt[:include]\r
+      r = Panel.show_opt[:include]\r
       r.has_key?(:author).should be_true\r
     end\r
   end\r
       r.has_key?(:author).should be_true\r
     end\r
   end\r
-  \r
-  describe '自分のコマ一覧取得に於いて' do\r
+  describe 'json単体出力オプションに於いて' do\r
+  end\r
+  describe 'コマ部品集合に於いて' do\r
     before do\r
     before do\r
+      #コマを作成しておく。\r
       @panel = FactoryGirl.create :panel, :author_id => @author.id\r
       @panel = FactoryGirl.create :panel, :author_id => @author.id\r
+      @pp = FactoryGirl.create :panel_picture, :panel_id => @panel.id, :t => 1, :width => @p.width, :height => @p.height\r
+      @sb = @panel.speech_balloons.create(\r
+        FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 0)\r
+      )\r
+      @gc = @panel.ground_colors.create(\r
+        FactoryGirl.attributes_for(:ground_color, :panel_id => @panel.id, :color_id => @color.id)\r
+      )\r
+      @gp = @panel.ground_pictures.create(\r
+        FactoryGirl.attributes_for(:ground_picture, :panel_id => @panel.id, :picture_id => @p.id)\r
+      )\r
+      @pc = @panel.panel_colors.create(\r
+        FactoryGirl.attributes_for(:panel_color, :panel_id => @panel.id, :code => 0xff0000)\r
+      )\r
+      @panel.reload\r
+    end\r
+    it 'リストを返している' do\r
+      r = @panel.parts_element\r
+      r.is_a?(Array).should be_true\r
+    end\r
+    it 'コマ絵とフキダシを合わせている' do\r
+      r = @panel.parts_element\r
+      r.include?(@pp).should be_true\r
+      r.include?(@sb).should be_true\r
+    end\r
+    it '景色素材と景色カラーと景色カラーコードを含んでいない' do\r
+      r = @panel.parts_element\r
+      r.include?(@gc).should_not be_true\r
+      r.include?(@gp).should_not be_true\r
+      r.include?(@pc).should_not be_true\r
     end\r
     end\r
-    it 'リストを返す' do\r
-      pl = Panel.mylist @author\r
-      pl.should eq [@panel]\r
+  end\r
+  describe 'コマ部品に於いて' do\r
+    before do\r
+      #コマを作成しておく。\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
+      @pp = FactoryGirl.create :panel_picture, :panel_id => @panel.id, :t => 1, :width => @p.width, :height => @p.height\r
+      @sb = @panel.speech_balloons.create(\r
+        FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 0)\r
+      )\r
+      @gc = @panel.ground_colors.create(\r
+        FactoryGirl.attributes_for(:ground_color, :panel_id => @panel.id, :color_id => @color.id)\r
+      )\r
+      @gp = @panel.ground_pictures.create(\r
+        FactoryGirl.attributes_for(:ground_picture, :panel_id => @panel.id, :picture_id => @p.id)\r
+      )\r
+      @pc = @panel.panel_colors.create(\r
+        FactoryGirl.attributes_for(:panel_color, :panel_id => @panel.id, :code => 0xff0000)\r
+      )\r
+      @panel.reload\r
     end\r
     end\r
-    it '時系列で並んでいる' do\r
-      npl = FactoryGirl.create :panel, :author_id => @author.id, :updated_at => Time.now + 100\r
-      pl = Panel.mylist @author\r
-      pl.should eq [npl, @panel]\r
+    context 'つつがなく終わるとき' do\r
+      it 'コマ部品集合を利用している' do\r
+        Panel.any_instance.stub(:parts_element).with(any_args).and_return([])\r
+        Panel.any_instance.should_receive(:parts_element).with(any_args).exactly(1)\r
+        r = @panel.parts\r
+      end\r
     end\r
     end\r
-    it '他人のコマは公開でも含まない' do\r
-      npl = FactoryGirl.create :panel, :author_id => @other_author.id, :publish => 1\r
-      pl = Panel.mylist @author\r
-      pl.should eq [@panel]\r
+    it 'リストを返している' do\r
+      r = @panel.parts\r
+      r.is_a?(Array).should be_true\r
+      r.size.should eq 2\r
     end\r
     end\r
-    it '自分のコマは非公開でも含んでいる' do\r
-      npl = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0, :updated_at => Time.now + 100\r
-      pl = Panel.mylist @author\r
-      pl.should eq [npl, @panel]\r
+    it 'tでソートしている' do\r
+      r = @panel.parts\r
+      r[0].should eq @sb\r
+      r[1].should eq @pp\r
+    end\r
+    context 'さらに末尾にフキダシを追加したとき' do\r
+      before do\r
+        @sb2 = @panel.speech_balloons.create(\r
+          FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 2)\r
+        )\r
+        @panel.reload\r
+      end\r
+      it 'tでソートしている' do\r
+        r = @panel.parts\r
+        r[0].should eq @sb\r
+        r[1].should eq @pp\r
+        r[2].should eq @sb2\r
+      end\r
     end\r
   end\r
     end\r
   end\r
-  \r
-  #異常データ検出\r
-    #コマはコミックに従属しなくなったのでtで入れ替えるチェックは要らなくなった\r
-    #コマ絵とフキダシの整合チェックをする\r
-  describe 'id収集に於いて' do\r
+  describe 'コマ地に於いて' do\r
+    before do\r
+      #コマを作成しておく。\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
+      @pp = FactoryGirl.create :panel_picture, :panel_id => @panel.id, :t => 1, :width => @p.width, :height => @p.height\r
+      @sb = @panel.speech_balloons.create(\r
+        FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 0)\r
+      )\r
+      @gc = @panel.ground_colors.create(\r
+        FactoryGirl.attributes_for(:ground_color, :panel_id => @panel.id, :color_id => @color.id)\r
+      )\r
+      @gp = @panel.ground_pictures.create(\r
+        FactoryGirl.attributes_for(:ground_picture, :panel_id => @panel.id, :picture_id => @p.id)\r
+      )\r
+      @pc = @panel.panel_colors.create(\r
+        FactoryGirl.attributes_for(:panel_color, :panel_id => @panel.id, :code => 0xff0000)\r
+      )\r
+      @panel.reload\r
+    end\r
+    it 'リストを返している' do\r
+      r = @panel.grounds\r
+      r.is_a?(Array).should be_true\r
+    end\r
+    it '景色素材と景色カラーと景色カラーコードを合わせている' do\r
+      r = @panel.grounds\r
+      r.include?(@gc).should be_true\r
+      r.include?(@gp).should be_true\r
+      r.include?(@pc).should be_true\r
+    end\r
+    it 'コマ絵とフキダシを含んでいない' do\r
+      r = @panel.grounds\r
+      r.include?(@pp).should_not be_true\r
+      r.include?(@sb).should_not be_true\r
+    end\r
+  end\r
+  describe 'コマ要素に於いて' do\r
+    before do\r
+      #コマを作成しておく。\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
+      @pp = FactoryGirl.create :panel_picture, :panel_id => @panel.id, :t => 1, :width => @p.width, :height => @p.height\r
+      @sb = @panel.speech_balloons.create(\r
+        FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 0)\r
+      )\r
+      @gc = @panel.ground_colors.create(\r
+        FactoryGirl.attributes_for(:ground_color, :panel_id => @panel.id, :color_id => @color.id)\r
+      )\r
+      @gp = @panel.ground_pictures.create(\r
+        FactoryGirl.attributes_for(:ground_picture, :panel_id => @panel.id, :picture_id => @p.id)\r
+      )\r
+      @pc = @panel.panel_colors.create(\r
+        FactoryGirl.attributes_for(:panel_color, :panel_id => @panel.id, :code => 0xff0000)\r
+      )\r
+      @panel.reload\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it 'コマ部品を利用している' do\r
+        Panel.any_instance.stub(:parts).with(any_args).and_return([])\r
+        Panel.any_instance.should_receive(:parts).with(any_args).exactly(1)\r
+        r = @panel.panel_elements\r
+      end\r
+      it 'コマ地を利用している' do\r
+        Panel.any_instance.stub(:grounds).with(any_args).and_return([])\r
+        Panel.any_instance.should_receive(:grounds).with(any_args).exactly(1)\r
+        r = @panel.panel_elements\r
+      end\r
+    end\r
+    it 'リストを返している' do\r
+      r = @panel.panel_elements\r
+      r.is_a?(Array).should be_true\r
+    end\r
+    it 'コマ絵とフキダシを合わせている' do\r
+      r = @panel.panel_elements\r
+      r.include?(@pp).should be_true\r
+      r.include?(@sb).should be_true\r
+    end\r
+    it '景色素材と景色カラーと景色カラーコードを合わせている' do\r
+      r = @panel.panel_elements\r
+      r.include?(@gc).should be_true\r
+      r.include?(@gp).should be_true\r
+      r.include?(@pc).should be_true\r
+    end\r
+    it 'tでソートしている[t順にソートできる部品の方が優先順位は高い。]' do\r
+      r = @panel.panel_elements\r
+      r[0].should eq @sb\r
+      r[1].should eq @pp\r
+    end\r
+  end\r
+  describe 'コマ要素のjson出力に於いて' do\r
+    before do\r
+      #コマを作成しておく。\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
+      @pp = FactoryGirl.create :panel_picture, :panel_id => @panel.id, :t => 1, :width => @p.width, :height => @p.height\r
+      @sb = @panel.speech_balloons.create(\r
+        FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 0)\r
+      )\r
+      @gc = @panel.ground_colors.create(\r
+        FactoryGirl.attributes_for(:ground_color, :panel_id => @panel.id, :color_id => @color.id)\r
+      )\r
+      @gp = @panel.ground_pictures.create(\r
+        FactoryGirl.attributes_for(:ground_picture, :panel_id => @panel.id, :picture_id => @p.id)\r
+      )\r
+      @pc = @panel.panel_colors.create(\r
+        FactoryGirl.attributes_for(:panel_color, :panel_id => @panel.id, :code => 0xff0000)\r
+      )\r
+      @panel.reload\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      before do\r
+        Panel.stub(:elm_json_opt).with(@pp).and_return({})\r
+        Panel.stub(:elm_json_opt).with(@sb).and_return({})\r
+        Panel.stub(:elm_json_opt).with(@gp).and_return({})\r
+        Panel.stub(:elm_json_opt).with(@gc).and_return({})\r
+        Panel.stub(:elm_json_opt).with(@pc).and_return({})\r
+      end\r
+      it 'コマ要素のjson出力オプションにコマ絵json出力オプションを依頼している' do\r
+        Panel.should_receive(:elm_json_opt).with(@pp).exactly(1)\r
+        r = @panel.elements\r
+      end\r
+      it 'コマ要素のjson出力オプションにフキダシjson出力オプションを依頼している' do\r
+        Panel.should_receive(:elm_json_opt).with(@sb).exactly(1)\r
+        r = @panel.elements\r
+      end\r
+      it 'コマ要素のjson出力オプションに景色素材json出力オプションを依頼している' do\r
+        Panel.should_receive(:elm_json_opt).with(@gp).exactly(1)\r
+        r = @panel.elements\r
+      end\r
+      it 'コマ要素のjson出力オプションに景色カラーjson出力オプションを依頼している' do\r
+        Panel.should_receive(:elm_json_opt).with(@gc).exactly(1)\r
+        r = @panel.elements\r
+      end\r
+      it 'コマ要素のjson出力オプションに景色カラーコードjson出力オプションを依頼している' do\r
+        Panel.should_receive(:elm_json_opt).with(@pc).exactly(1)\r
+        r = @panel.elements\r
+      end\r
+    end\r
+    it 'リストを返している' do\r
+      r = @panel.elements\r
+      r.is_a?(Array).should be_true\r
+    end\r
+  end\r
+  describe 'コマのjson出力に於いて' do\r
+    before do\r
+      #コマを作成しておく。\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
+      @pp = FactoryGirl.create :panel_picture, :panel_id => @panel.id, :t => 1, :width => @p.width, :height => @p.height\r
+      @sb = @panel.speech_balloons.create(\r
+        FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 0)\r
+      )\r
+      @gc = @panel.ground_colors.create(\r
+        FactoryGirl.attributes_for(:ground_color, :panel_id => @panel.id, :color_id => @color.id)\r
+      )\r
+      @gp = @panel.ground_pictures.create(\r
+        FactoryGirl.attributes_for(:ground_picture, :panel_id => @panel.id, :picture_id => @p.id)\r
+      )\r
+      @pc = @panel.panel_colors.create(\r
+        FactoryGirl.attributes_for(:panel_color, :panel_id => @panel.id, :code => 0xff0000)\r
+      )\r
+      @panel.reload\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      before do\r
+        Panel.any_instance.stub(:elements).with(any_args).and_return({})\r
+      end\r
+      it 'コマ要素のjson出力を依頼している' do\r
+        Panel.any_instance.should_receive(:elements).with(any_args).exactly(1)\r
+        r = @panel.panel_elements_as_json\r
+      end\r
+    end\r
+    it 'json textを返している' do\r
+      r = JSON.parse @panel.panel_elements_as_json\r
+      r.is_a?(Hash).should be_true\r
+    end\r
+    it 'author,コマ要素を含んでいる' do\r
+      r = JSON.parse @panel.panel_elements_as_json\r
+      r.has_key?('author').should be_true\r
+      r.has_key?('elements').should be_true\r
+      #t:0\r
+      sb = r['elements'].first\r
+      sb.has_key?('classname').should be_true\r
+      sb.has_key?('balloons').should be_true\r
+      sb.has_key?('speeches').should be_true\r
+      #t:1\r
+    end\r
+  end\r
+  describe '検証値収集に於いて' do\r
     context 'つつがなく終わるとき' do\r
     context 'つつがなく終わるとき' do\r
-      it '第一パラメータで指定された配列中から第二引数のidを収集している' do\r
-        a = [[{:panel_id => 1, :a => 'a'}, {:panel_id => 2, :a => 'a'}], \r
+      it '第一パラメータで指定された配列中から第二引数のカラム値を収集している' do\r
+        elements = [[{:panel_id => 1, :a => 'a'}, {:panel_id => 2, :a => 'a'}], \r
           [{:panel_id => 3, :a => 'a'}, {:panel_id => 4, :a => 'a'}]]\r
           [{:panel_id => 3, :a => 'a'}, {:panel_id => 4, :a => 'a'}]]\r
-        r = Panel.collect_element_value a, :panel_id\r
+        r = Panel.collect_element_value elements, :panel_id\r
         r.should eq [1, 2, 3, 4]\r
       end\r
         r.should eq [1, 2, 3, 4]\r
       end\r
+      it '第一パラメータで指定された配列中から第二引数のカラム値を収集している' do\r
+        elements = [[{:t => 1, :a => 'a'}, {:t => 2, :a => 'a'}], \r
+          [{:t => 3, :a => 'a'}, {:t => 0, :a => 'a'}]]\r
+        r = Panel.collect_element_value elements, :t\r
+        r.should eq [1, 2, 3, 0]\r
+      end\r
     end\r
     end\r
-    context 'Nil除外指示があるとき' do\r
-      it '収集したpanel_idのうちnilは除外している' do\r
-        a = [[{:panel_id => 1, :a => 'a'}, {:panel_id => 2, :a => 'a'}, {:panel_id => nil, :a => 'a'}], \r
-          [{:panel_id => 3, :a => 'a'}, {:panel_id => nil, :a => 'a'}, {:panel_id => 4, :a => 'a'}]]\r
-        r = Panel.collect_element_value a, :panel_id, true\r
-        r.should eq [1, 2, 3, 4]\r
+  end\r
+  describe 'シリアライズチェックに於いて' do\r
+    context 'つつがなく終わるとき' do\r
+      it '0からシリアライズされているならTrueを返す' do\r
+        r = Panel.validate_t [0, 1, 2]\r
+        r.should be_true\r
+      end\r
+      it '見た目はシリアライズされてなくてもソート結果が無事ならtrueを返す' do\r
+        r = Panel.validate_t [0, 2, 1]\r
+        r.should be_true\r
+      end\r
+      it '見た目はシリアライズされてなくてもソート結果が無事ならtrueを返す' do\r
+        r = Panel.validate_t [ 2, 1, 4, 3, 0]\r
+        r.should be_true\r
+      end\r
+    end\r
+    context '異常なとき' do\r
+      it '0から始まらないならFalseを返す' do\r
+        r = Panel.validate_t [1, 2, 3]\r
+        r.should be_false\r
+      end\r
+      it '連続していないならFalseを返す' do\r
+        r = Panel.validate_t [0, 1, 2, 4]\r
+        r.should be_false\r
+      end\r
+      it '連続していないならFalseを返す' do\r
+        r = Panel.validate_t [0, 1, 2, 4, 5]\r
+        r.should be_false\r
+      end\r
+    end\r
+  end\r
+  describe 'tチェック単体に於いて' do\r
+    before do\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      it '検証値収集を依頼している' do\r
+        Panel.should_receive(:collect_element_value).with(any_args).exactly(1)\r
+        Panel.stub(:collect_element_value).with(any_args).and_return([])\r
+        Panel.stub(:validate_t).with(any_args).and_return(true)\r
+        r = Panel.validate_element_t [], :t\r
+      end\r
+      it 'シリアライズチェック依頼している' do\r
+        Panel.stub(:collect_element_value).with(any_args).and_return([])\r
+        Panel.should_receive(:validate_t).with(any_args).exactly(1)\r
+        Panel.stub(:validate_t).with(any_args).and_return(true)\r
+        r = Panel.validate_element_t [], :t\r
+      end\r
+    end\r
+  end\r
+  describe '従属データの検証に於いて' do\r
+    context 'つつがなく終わるとき' do\r
+      it 'trueを返している' do\r
+        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
+        @panel.panel_pictures.build(\r
+          FactoryGirl.attributes_for(:panel_picture, :panel_id => @panel.id, :picture_id => @p.id, :t => 0)\r
+        )\r
+        @panel.panel_pictures.build(\r
+          FactoryGirl.attributes_for(:panel_picture, :panel_id => @panel.id, :picture_id => @p.id, :t => 1)\r
+        )\r
+        sb1 = @panel.speech_balloons.build(\r
+          FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 2)\r
+        )\r
+        sb1.balloons.build(\r
+          FactoryGirl.attributes_for(:balloon, :speech_balloon_id => sb1.id)\r
+        )\r
+        sb1.speeches.build(\r
+          FactoryGirl.attributes_for(:speech, :speech_balloon_id => sb1.id)\r
+        )\r
+        sb2 = @panel.speech_balloons.build(\r
+          FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 3)\r
+        )\r
+        sb2.balloons.build(\r
+          FactoryGirl.attributes_for(:balloon, :speech_balloon_id => sb2.id)\r
+        )\r
+        sb2.speeches.build(\r
+          FactoryGirl.attributes_for(:speech, :speech_balloon_id => sb2.id)\r
+        )\r
+        r = @panel.validate_child\r
+        r.should be_true\r
+      end\r
+    end\r
+    context 'シリアライズされていないとき' do\r
+      it 'falseを返している' do\r
+        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
+        @panel.panel_pictures.build(\r
+          FactoryGirl.attributes_for(:panel_picture, :panel_id => @panel.id, :picture_id => @p.id, :t => 0)\r
+        )\r
+        @panel.panel_pictures.build(\r
+          FactoryGirl.attributes_for(:panel_picture, :panel_id => @panel.id, :picture_id => @p.id, :t => 1)\r
+        )\r
+        sb1 = @panel.speech_balloons.build(\r
+          FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 2)\r
+        )\r
+        sb1.balloons.build(\r
+          FactoryGirl.attributes_for(:balloon, :speech_balloon_id => sb1.id)\r
+        )\r
+        sb1.speeches.build(\r
+          FactoryGirl.attributes_for(:speech, :speech_balloon_id => sb1.id)\r
+        )\r
+        sb2 = @panel.speech_balloons.build(\r
+          FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 4)\r
+        )\r
+        sb2.balloons.build(\r
+          FactoryGirl.attributes_for(:balloon, :speech_balloon_id => sb2.id)\r
+        )\r
+        sb2.speeches.build(\r
+          FactoryGirl.attributes_for(:speech, :speech_balloon_id => sb2.id)\r
+        )\r
+        r = @panel.validate_child\r
+        r.should be_false\r
+      end\r
+    end\r
+  end\r
+  describe '保存に於いて' do\r
+    before do\r
+      @attr = FactoryGirl.attributes_for :panel\r
+      @panel = Panel.new
+      @panel.supply_default
+    end\r
+    context 'つつがなく終わるとき' do\r
+      before do\r
+        Panel.any_instance.stub(:validate_child).with(any_args).and_return(true)\r
+        Panel.any_instance.stub(:save).with(any_args).and_return(true)\r
+      end\r
+      it 'コマモデルに上書き補充を依頼している' do\r
+        Panel.any_instance.should_receive(:overwrite).exactly(1)\r
+        r = @panel.store @attr, @author\r
+      end\r
+      it '従属データの検証を依頼している' do\r
+        Panel.any_instance.should_receive(:validate_child).with(any_args).exactly(1)\r
+        r = @panel.store @attr, @author\r
+      end\r
+      it '保存を依頼している' do\r
+        Panel.any_instance.should_receive(:save).with(any_args).exactly(1)\r
+        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
+        r = @panel.store @attr, @author\r
+      end\r
+    end\r
+    context 'つつがなく終わるとき' do\r
+      before do\r
+        Panel.any_instance.stub(:validate_child).with(any_args).and_return(true)\r
+      end\r
+      it 'Trueを返す' do\r
+        r = @panel.store @attr, @author\r
+        r.should be_true\r
+      end\r
+      it '行が追加されている' do\r
+        Panel.any_instance.stub(:validate_child).with(any_args).and_return(true)\r
+        lambda {\r
+          r = @panel.store @attr, @author\r
+        }.should change(Panel, :count)\r
+      end\r
+    end\r
+    context '従属データの検証に失敗したとき' do\r
+      before do\r
+        Panel.any_instance.stub(:validate_child).with(any_args).and_return(false)\r
+      end\r
+      it 'エラーメッセージがセットされている' do\r
+        r = @panel.store @attr, @author\r
+        @panel.errors.should_not be_empty\r
+      end\r
+    end\r
+    context 'カラム値がFalseしたとき' do\r
+      before do\r
+        Panel.any_instance.stub(:validate_child).with(any_args).and_return(true)\r
       end\r
       end\r
+      it 'エラーメッセージがセットされている' do\r
+        r = @panel.store false, @author\r
+        @panel.errors.should_not be_empty\r
+      end\r
+    end\r
+  end\r
+=begin\r
+  describe 'id挿げ替え防止確認に於いて' do\r
+    before do\r
+      #コマを作成しておく。\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
+      @pp = FactoryGirl.create :panel_picture, :panel_id => @panel.id, :t => 1, :width => @p.width, :height => @p.height\r
+      @sb = @panel.speech_balloons.create(\r
+        FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 0)\r
+      )\r
+      @gc = @panel.ground_colors.create(\r
+        FactoryGirl.attributes_for(:ground_color, :panel_id => @panel.id, :color_id => @color.id)\r
+      )\r
+      @gp = @panel.ground_pictures.create(\r
+        FactoryGirl.attributes_for(:ground_picture, :panel_id => @panel.id, :picture_id => @p.id)\r
+      )\r
+      @pc = @panel.panel_colors.create(\r
+        FactoryGirl.attributes_for(:panel_color, :panel_id => @panel.id, :code => 0xff0000)\r
+      )\r
+      @panel.reload\r
+    end\r
+    it 'author,コマ要素を含んでいる' do\r
+      @panel2 = FactoryGirl.create :panel, :author_id => @author.id\r
+      @panel2.panel_pictures.create(\r
+        FactoryGirl.attributes_for(:panel_picture, :panel_id => @panel.id, :t => 1, :width => @p.width, :height => @p.height)\r
+      )\r
+      @panel2.save!\r
+      p @panel2\r
+      p @panel2.panel_pictures\r
     end\r
   end\r
   describe 'id一致チェックに於いて' do\r
     end\r
   end\r
   describe 'id一致チェックに於いて' do\r
@@ -890,236 +1284,5 @@ describe Panel do
       end\r
     end\r
   end\r
       end\r
     end\r
   end\r
-  describe 'シリアライズチェックに於いて' do\r
-    context 'つつがなく終わるとき' do\r
-      it '0からシリアライズされているならTrueを返す' do\r
-        r = Panel.validate_t [0, 1, 2]\r
-        r.should be_true\r
-      end\r
-      it '見た目はシリアライズされてなくてもソート結果が無事ならtrueを返す' do\r
-        r = Panel.validate_t [0, 2, 1]\r
-        r.should be_true\r
-      end\r
-      it '見た目はシリアライズされてなくてもソート結果が無事ならtrueを返す' do\r
-        r = Panel.validate_t [ 2, 1, 4, 3, 0]\r
-        r.should be_true\r
-      end\r
-    end\r
-    context '異常なとき' do\r
-      it '0から始まらないならFalseを返す' do\r
-        r = Panel.validate_t [1, 2, 3]\r
-        r.should be_false\r
-      end\r
-      it '連続していないならFalseを返す' do\r
-        r = Panel.validate_t [0, 1, 2, 4]\r
-        r.should be_false\r
-      end\r
-      it '連続していないならFalseを返す' do\r
-        r = Panel.validate_t [0, 1, 2, 4, 5]\r
-        r.should be_false\r
-      end\r
-    end\r
-  end\r
-  describe 'tチェック単体に於いて' do\r
-    before do\r
-    end\r
-    context 'つつがなく終わるとき' do\r
-      it 'コマ絵とフキダシのtを収集依頼している' do\r
-        Panel.should_receive(:collect_element_value).with(any_args).exactly(1)\r
-        Panel.stub(:collect_element_value).with(any_args).and_return([])\r
-        Panel.stub(:validate_t).with(any_args).and_return(true)\r
-        r = Panel.validate_element_t [], :t\r
-      end\r
-      it '収集したtをシリアライズチェック依頼している' do\r
-        Panel.stub(:collect_element_value).with(any_args).and_return([])\r
-        Panel.should_receive(:validate_t).with(any_args).exactly(1)\r
-        Panel.stub(:validate_t).with(any_args).and_return(true)\r
-        r = Panel.validate_element_t [], :t\r
-      end\r
-    end\r
-    #実データでチェック\r
-    #依頼チェックだけでは不安なので最低限のチェックを\r
-    context '新規のとき' do\r
-      it 'コマ絵で正常通過している' do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-        @panel.panel_pictures.build(\r
-          FactoryGirl.attributes_for(:panel_picture, :panel_id => nil, :picture_id => @p.id, :t => nil)\r
-        )\r
-        r = Panel.validate_element_t [@panel.panel_pictures, @panel.speech_balloons], :t\r
-        r.should be_true\r
-      end\r
-      it 'フキダシで正常通過している' do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-        @panel.speech_balloons.build(\r
-          FactoryGirl.attributes_for(:speech_balloon, :panel_id => nil, :speech_balloon_template_id => @sbt.id, :t => nil)\r
-        )\r
-        r = Panel.validate_element_t [@panel.panel_pictures, @panel.speech_balloons], :t\r
-        r.should be_true\r
-      end\r
-    end\r
-    context '既存のとき' do\r
-      it 'コマ絵で正常通過している' do\r
-        @panel = FactoryGirl.create :panel, :author_id => @author.id\r
-        @panel.panel_pictures.build(\r
-          FactoryGirl.attributes_for(:panel_picture, :panel_id => @panel.id, :picture_id => @p.id, :t => 0)\r
-        )\r
-        r = Panel.validate_element_t [@panel.panel_pictures, @panel.speech_balloons], :t\r
-        r.should be_true\r
-      end\r
-      it 'フキダシで正常通過している' do\r
-        @panel = FactoryGirl.create :panel, :author_id => @author.id\r
-        @panel.speech_balloons.build(\r
-          FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 0)\r
-        )\r
-        r = Panel.validate_element_t [@panel.panel_pictures, @panel.speech_balloons], :t\r
-        r.should be_true\r
-      end\r
-    end\r
-  end\r
-  describe '複合チェックに於いて' do\r
-    context 'つつがなく終わるとき' do\r
-      it 'している' do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-        @panel.panel_pictures.build(\r
-          FactoryGirl.attributes_for(:panel_picture, :panel_id => @panel.id, :picture_id => @p.id, :t => 0)\r
-        )\r
-        @panel.panel_pictures.build(\r
-          FactoryGirl.attributes_for(:panel_picture, :panel_id => @panel.id, :picture_id => @p.id, :t => 1)\r
-        )\r
-        sb1 = @panel.speech_balloons.build(\r
-          FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 2)\r
-        )\r
-        sb1.balloons.build(\r
-          FactoryGirl.attributes_for(:balloon, :speech_balloon_id => sb1.id)\r
-        )\r
-        sb1.speeches.build(\r
-          FactoryGirl.attributes_for(:speech, :speech_balloon_id => sb1.id)\r
-        )\r
-        sb2 = @panel.speech_balloons.build(\r
-          FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 3)\r
-        )\r
-        sb2.balloons.build(\r
-          FactoryGirl.attributes_for(:balloon, :speech_balloon_id => sb2.id)\r
-        )\r
-        sb2.speeches.build(\r
-          FactoryGirl.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 'している' do\r
-        @panel = FactoryGirl.build :panel, :author_id => @author.id\r
-        @panel.panel_pictures.build(\r
-          FactoryGirl.attributes_for(:panel_picture, :panel_id => @panel.id, :picture_id => @p.id, :t => 0)\r
-        )\r
-        @panel.panel_pictures.build(\r
-          FactoryGirl.attributes_for(:panel_picture, :panel_id => @panel.id, :picture_id => @p.id, :t => 1)\r
-        )\r
-        sb1 = @panel.speech_balloons.build(\r
-          FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 2)\r
-        )\r
-        sb1.balloons.build(\r
-          FactoryGirl.attributes_for(:balloon, :speech_balloon_id => sb1.id)\r
-        )\r
-        sb1.speeches.build(\r
-          FactoryGirl.attributes_for(:speech, :speech_balloon_id => sb1.id)\r
-        )\r
-        sb2 = @panel.speech_balloons.build(\r
-          FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 3)\r
-        )\r
-        sb2.balloons.build(\r
-          FactoryGirl.attributes_for(:balloon, :speech_balloon_id => sb2.id)\r
-        )\r
-        sb2.speeches.build(\r
-          FactoryGirl.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 = FactoryGirl.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 = FactoryGirl.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 = FactoryGirl.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 = FactoryGirl.create :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 = FactoryGirl.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 = FactoryGirl.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 = FactoryGirl.create :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 = FactoryGirl.create :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 = FactoryGirl.create :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 = FactoryGirl.create :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 = FactoryGirl.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
 end\r
 end\r
index bdda015..dfd0e84 100644 (file)
@@ -7,11 +7,16 @@ describe Story do
     @sp = FactoryGirl.create :system_picture
     @lg = FactoryGirl.create :license_group
     @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
     @sp = FactoryGirl.create :system_picture
     @lg = FactoryGirl.create :license_group
     @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+    @color = FactoryGirl.create :color
     @user = FactoryGirl.create( :user_yas)
     @author = @user.author
     @artist = FactoryGirl.create :artist_yas, :author_id => @author.id
     @other_user = FactoryGirl.create( :user_yas)
     @other_author = @other_user.author
     @user = FactoryGirl.create( :user_yas)
     @author = @user.author
     @artist = FactoryGirl.create :artist_yas, :author_id => @author.id
     @other_user = FactoryGirl.create( :user_yas)
     @other_author = @other_user.author
+    @op = FactoryGirl.create :original_picture, :artist_id => @artist.id\r
+    @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id\r
+    @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id\r
+    @sbt = FactoryGirl.create :speech_balloon_template\r
   end
   
   describe '検証に於いて' do
   end
   
   describe '検証に於いて' do
@@ -195,19 +200,19 @@ describe Story do
       end
     end
     it 'リストを返す' do
       end
     end
     it 'リストを返す' do
-      c = Story.list @comic, @author
+      c = Story.play_list @comic, @author
       c.should eq [@story]
     end
     it 't順で並んでいる' do
       #公開コミックの公開コマは(他人のコミックであっても)含んでいる
       v = FactoryGirl.create :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 1
       c.should eq [@story]
     end
     it 't順で並んでいる' do
       #公開コミックの公開コマは(他人のコミックであっても)含んでいる
       v = FactoryGirl.create :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 1
-      c = Story.list @comic, @author
+      c = Story.play_list @comic, @author
       c.should eq [ @story, v]
     end
       c.should eq [ @story, v]
     end
-    it 'é\9d\9eå\85¬é\96\8bã\81®ã\82³ã\83\9eã\81¯å\90«ã\81¾ã\81ªã\81\84' do
+    it 'é\9d\9eå\85¬é\96\8bã\81®ã\82³ã\83\9eã\81¯å\90«ã\82\93ã\81§ã\81\84ã\82\8b' do
       h = FactoryGirl.create :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel2.id, :t => 1
       h = FactoryGirl.create :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel2.id, :t => 1
-      c = Story.list @comic, @author
-      c.should eq [ @story]
+      c = Story.play_list @comic, @author
+      c.should eq [ @story, h]
     end
     context 'DBに5件あって1ページの件数を2件に変えたとして' do
       before do
     end
     context 'DBに5件あって1ページの件数を2件に変えたとして' do
       before do
@@ -218,15 +223,15 @@ describe Story do
       end
       it 'offset=0なら末尾2件を返す' do
         #時系列で並んでいる
       end
       it 'offset=0なら末尾2件を返す' do
         #時系列で並んでいる
-        c = Story.list( @comic, @author, 0, 2)
+        c = Story.play_list( @comic, @author, 0, 2)
         c.should eq [@story, @story2]
       end
       it 'offset=2なら中間2件を返す' do
         c.should eq [@story, @story2]
       end
       it 'offset=2なら中間2件を返す' do
-        c = Story.list(@comic, @author, 2, 2)
+        c = Story.play_list(@comic, @author, 2, 2)
         c.should eq [@story3, @story4]
       end
       it 'offset=4なら先頭1件を返す' do
         c.should eq [@story3, @story4]
       end
       it 'offset=4なら先頭1件を返す' do
-        c = Story.list(@comic, @author, 4, 2)
+        c = Story.play_list(@comic, @author, 4, 2)
         c.should eq [@story5]
       end
     end
         c.should eq [@story5]
       end
     end
@@ -290,71 +295,17 @@ describe Story do
         end
   end
   describe 'json一覧出力オプションに於いて' do
         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][:panel_pictures].has_key?(:picture).should be_true
-        end
-          it '実素材は絵師を含んでいる' do
-            r = Story.list_json_opt[:include]
-            r[:panel][:panel_pictures][:picture].has_key?(:artist).should be_true
-          end
-          it '実素材はライセンスを含んでいる' do
-            r = Story.list_json_opt[:include]
-            r[:panel][:panel_pictures][:picture].has_key?(:license).should be_true
-          end
-      it 'コマはフキダシを含んでいる' do
-        r = Story.list_json_opt[:include]
-        r[:panel].has_key?(:speech_balloons).should be_true
-      end
-        it 'フキダシはフキダシ枠を含んでいる' do
-          r = Story.list_json_opt[:include]
-          r[:panel][:speech_balloons].has_key?(:balloons).should be_true
-        end
-        it 'フキダシはセリフを含んでいる' do
-          r = Story.list_json_opt[:include]
-          r[:panel][:speech_balloons].has_key?(:speeches).should be_true
-        end
   end
   
   describe '自分のストーリー一覧取得に於いて' do
     before do
   end
   
   describe '自分のストーリー一覧取得に於いて' do
     before do
-      @comic = FactoryGirl.create :comic, :author_id => @author.id, :visible => 0
-      @panel = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0
+      @comic = FactoryGirl.create :comic, :author_id => @author.id, :visible => 1
+      @panel = FactoryGirl.create :panel, :author_id => @author.id, :publish => 1
       @story = FactoryGirl.create :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
       @other_comic = FactoryGirl.create :comic, :author_id => @other_author.id, :visible => 1
       @other_panel = FactoryGirl.create :panel, :author_id => @other_author.id, :publish => 1
       @story = FactoryGirl.create :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
       @other_comic = FactoryGirl.create :comic, :author_id => @other_author.id, :visible => 1
       @other_panel = FactoryGirl.create :panel, :author_id => @other_author.id, :publish => 1
+      @hcomic = FactoryGirl.create :comic, :author_id => @author.id, :visible => 0
+      @hpanel = FactoryGirl.create :panel, :author_id => @author.id, :publish => 0
     end
     context 'つつがなく終わるとき' do\r
       it '一覧取得オプションを利用している' do\r
     end
     context 'つつがなく終わるとき' do\r
       it '一覧取得オプションを利用している' do\r
@@ -377,10 +328,10 @@ describe Story do
       sl = Story.mylist @author
       sl.should eq [@story]
     end
       sl = Story.mylist @author
       sl.should eq [@story]
     end
-    it '自分のストーリーはコマコミックともに非公開でも含んでいる' do
-      nc = FactoryGirl.create :comic, :author_id => @author.id, :visible => 0, :updated_at => Time.now + 100
-      cl = Comic.mylist @author
-      cl.should eq [nc, @story]
+    it '自分のストーリーはコマコミックともに非公開でも含んでいる' do
+      hs = FactoryGirl.create :story, :author_id => @author.id, :comic_id => @hcomic.id, :panel_id => @hpanel.id, :updated_at => Time.now + 100
+      sl = Story.mylist @author
+      sl.should eq [hs, @story]
     end
     context 'DBに5件あって1ページの件数を2件に変えたとして' do
       before do
     end
     context 'DBに5件あって1ページの件数を2件に変えたとして' do
       before do
@@ -519,62 +470,70 @@ describe Story do
         end
   end
   describe 'json単体取得オプションに於いて' do
         end
   end
   describe 'json単体取得オプションに於いて' do
-    it 'includeキーを含んでいる' do
-      r = Story.show_json_opt
-      r.has_key?(:include).should be_true
-    end
-    it '3つの項目を含んでいる' do
-      r = Story.show_json_opt[:include]
-      r.should have(3).items
-    end
-    it 'コミックを含んでいる' do
-      r = Story.show_json_opt[:include]
-      r.has_key?(:comic).should be_true
-    end
-      it 'コミックは作家を含んでいる' do
-        r = Story.show_json_opt[:include]
-        r[:comic].has_key?(:author).should be_true
-      end
-    it '作家を含んでいる' do
-      r = Story.show_json_opt[:include]
-      r.has_key?(:author).should be_true
-    end
-    it 'コマを含んでいる' do
-      r = Story.show_json_opt[:include]
-      r.has_key?(:panel).should be_true
-    end
-      it 'コマは作家を含んでいる' do
-        r = Story.show_json_opt[:include]
-        r[:panel].has_key?(:author).should be_true
-      end
-      it 'コマはコマ絵を含んでいる' do
-        r = Story.show_json_opt[:include]
-        r[:panel].has_key?(:panel_pictures).should be_true
-      end
-        it 'コマ絵は実素材を含んでいる' do
-          r = Story.show_json_opt[:include]
-          r[:panel][:panel_pictures].has_key?(:picture).should be_true
-        end
-          it '実素材は絵師を含んでいる' do
-            r = Story.show_json_opt[:include]
-            r[:panel][:panel_pictures][:picture].has_key?(:artist).should be_true
-          end
-          it '実素材はライセンスを含んでいる' do
-            r = Story.show_json_opt[:include]
-            r[:panel][:panel_pictures][:picture].has_key?(:license).should be_true
-          end
-      it 'コマはフキダシを含んでいる' do
-        r = Story.show_json_opt[:include]
-        r[:panel].has_key?(:speech_balloons).should be_true
-      end
-        it 'フキダシはフキダシ枠を含んでいる' do
-          r = Story.show_json_opt[:include]
-          r[:panel][:speech_balloons].has_key?(:balloons).should be_true
-        end
-        it 'フキダシはセリフを含んでいる' do
-          r = Story.show_json_opt[:include]
-          r[:panel][:speech_balloons].has_key?(:speeches).should be_true
-        end
+  end
+  
+  describe 'ストーリーのjson出力に於いて' do
+    before do\r
+      #コマを作成しておく。\r
+      @panel = FactoryGirl.create :panel, :author_id => @author.id\r
+      @pp = FactoryGirl.create :panel_picture, :panel_id => @panel.id, :t => 1, :width => @p.width, :height => @p.height\r
+      @sb = @panel.speech_balloons.create(\r
+        FactoryGirl.attributes_for(:speech_balloon, :panel_id => @panel.id, :speech_balloon_template_id => @sbt.id, :t => 0)\r
+      )\r
+      @gc = @panel.ground_colors.create(\r
+        FactoryGirl.attributes_for(:ground_color, :panel_id => @panel.id, :color_id => @color.id)\r
+      )\r
+      @gp = @panel.ground_pictures.create(\r
+        FactoryGirl.attributes_for(:ground_picture, :panel_id => @panel.id, :picture_id => @p.id)\r
+      )\r
+      @pc = @panel.panel_colors.create(\r
+        FactoryGirl.attributes_for(:panel_color, :panel_id => @panel.id, :code => 0xff0000)\r
+      )\r
+      @panel.reload\r
+      @comic = FactoryGirl.create :comic, :author_id => @author.id
+      @story = FactoryGirl.create :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+    end\r
+    context '事前チェックする' do
+      before do\r
+        Panel.any_instance.stub(:elements).and_return('{}')
+      end\r
+      it 'コマ要素のjson出力を依頼している' do\r
+        Panel.any_instance.stub(:visible?).with(any_args).and_return(true)
+        Panel.any_instance.should_receive(:elements).with(any_args).exactly(1)\r
+        r = @story.story_as_json @author
+      end\r
+    end\r
+    it 'json textを返している' do\r
+      r = JSON.parse @story.story_as_json(@author)\r
+      r.is_a?(Hash).should be_true\r
+    end\r
+    it 'comic,author,panel,コマ要素を含んでいる' do\r
+      r = JSON.parse @story.story_as_json(@author)\r
+      r.has_key?('comic').should be_true\r
+      r['comic'].has_key?('author').should be_true\r
+      r.has_key?('author').should be_true\r
+      r.has_key?('panel').should be_true\r
+      r['panel'].has_key?('author').should be_true\r
+    end\r
+    context 'コマ閲覧許可のとき' do
+      before do\r
+        Panel.any_instance.stub(:visible?).with(any_args).and_return(true)
+      end\r
+      it 'コマ要素にコマ要素を追加している' do\r
+        r = JSON.parse @story.story_as_json(@author)\r
+        r['panel'].has_key?('elements').should be_true\r
+        r['panel']['elements'].should_not be_empty\r
+      end\r
+    end\r
+    context 'コマ閲覧不許可のとき' do
+      before do\r
+        Panel.any_instance.stub(:visible?).with(any_args).and_return(false)
+      end\r
+      it 'コマ要素にデータを含ませない' do\r
+        r = JSON.parse @story.story_as_json(@author)\r
+        r['panel'].has_key?('elements').should be_false\r
+      end\r
+    end\r
   end
   
   describe 't補充値に於いて' do
   end
   
   describe 't補充値に於いて' do