table_cloth 0.2.3 → 0.3.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.gitignore +1 -0
  2. data/lib/generators/templates/table.rb +7 -0
  3. data/lib/table_cloth.rb +14 -15
  4. data/lib/table_cloth/base.rb +3 -26
  5. data/lib/table_cloth/column.rb +0 -12
  6. data/lib/table_cloth/{action.rb → column_jury.rb} +10 -6
  7. data/lib/table_cloth/configurable_elements.rb +6 -13
  8. data/lib/table_cloth/extensions/actions.rb +25 -0
  9. data/lib/table_cloth/extensions/actions/action.rb +21 -0
  10. data/lib/table_cloth/extensions/actions/action_collection.rb +11 -0
  11. data/lib/table_cloth/extensions/actions/column.rb +21 -0
  12. data/lib/table_cloth/extensions/actions/jury.rb +37 -0
  13. data/lib/table_cloth/presenter.rb +16 -5
  14. data/lib/table_cloth/presenters/default.rb +1 -1
  15. data/lib/table_cloth/version.rb +1 -1
  16. data/spec/factories/actions.rb +6 -0
  17. data/spec/factories/columns.rb +18 -0
  18. data/spec/factories/dummy_tables.rb +11 -0
  19. data/spec/lib/base_spec.rb +6 -22
  20. data/spec/lib/column_jury_spec.rb +35 -0
  21. data/spec/lib/column_spec.rb +9 -14
  22. data/spec/lib/extensions/actions/action_collection_spec.rb +29 -0
  23. data/spec/lib/extensions/actions/action_spec.rb +57 -0
  24. data/spec/lib/extensions/actions/column_spec.rb +23 -0
  25. data/spec/lib/extensions/actions/jury_spec.rb +67 -0
  26. data/spec/lib/extensions/actions_spec.rb +42 -0
  27. data/spec/lib/presenter_spec.rb +29 -31
  28. data/spec/lib/presenters/default_spec.rb +61 -124
  29. data/spec/spec_helper.rb +7 -0
  30. data/spec/support/dummy_table.rb +0 -4
  31. data/spec/support/dummy_table_with_value_options.rb +1 -1
  32. data/spec/support/matchers/element_matchers.rb +6 -0
  33. data/table_cloth.gemspec +2 -0
  34. metadata +63 -14
  35. data/lib/table_cloth/actions.rb +0 -23
  36. data/lib/table_cloth/columns/action.rb +0 -24
  37. data/spec/lib/actions_spec.rb +0 -28
  38. data/spec/lib/columns/action_spec.rb +0 -73
  39. data/spec/support/dummy_table_with_actions.rb +0 -7
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  *.gem
2
2
  *.rbc
3
3
  .bundle
4
+ coverage
4
5
  .config
5
6
  .yardoc
6
7
  Gemfile.lock
@@ -1,4 +1,7 @@
1
1
  class <%= class_name %>Table < TableCloth::Base
2
+ # To include actions on this table, uncomment this line
3
+ # include TableCloth::Extensions::Actions
4
+
2
5
  # Define columns with the #column method
3
6
  # column :name, :email
4
7
 
@@ -22,8 +25,12 @@ class <%= class_name %>Table < TableCloth::Base
22
25
  # Actions give you the ability to create a column for any actions you'd like to provide.
23
26
  # Pass a block with an arity of 2, (object, view context).
24
27
  # You can add as many actions as you want.
28
+ # Make sure you include the actions extension.
25
29
  #
26
30
  # actions do
27
31
  # action {|object| link_to "Edit", edit_object_path(object) }
32
+ # action(if: :valid?) {|object| link_to "Invalidate", invalidate_object_path(object) }
28
33
  # end
34
+ #
35
+ # If action provides an "if:" option, it will call that method on the object. It can also take a block with an arity of 1.
29
36
  end
data/lib/table_cloth.rb CHANGED
@@ -1,24 +1,23 @@
1
- require 'action_view'
2
- require 'active_support/core_ext/class'
3
- require 'table_cloth/version'
4
- require 'table_cloth/configurable_elements'
5
- require 'table_cloth/base'
1
+ require "action_view"
2
+ require "active_support/core_ext/class"
3
+ require "table_cloth/version"
4
+ require "table_cloth/configurable_elements"
5
+ require "table_cloth/base"
6
6
 
7
7
  module TableCloth
8
- autoload :Configuration, 'table_cloth/configuration'
9
- autoload :Builder, 'table_cloth/builder'
10
- autoload :Column, 'table_cloth/column'
11
- autoload :Action, 'table_cloth/action'
12
- autoload :Actions, 'table_cloth/actions'
13
- autoload :Presenter, 'table_cloth/presenter'
14
- autoload :ActionViewExtension, 'table_cloth/action_view_extension'
8
+ autoload :Configuration, "table_cloth/configuration"
9
+ autoload :Builder, "table_cloth/builder"
10
+ autoload :Column, "table_cloth/column"
11
+ autoload :ColumnJury, "table_cloth/column_jury"
12
+ autoload :Presenter, "table_cloth/presenter"
13
+ autoload :ActionViewExtension, "table_cloth/action_view_extension"
15
14
 
16
15
  module Presenters
17
- autoload :Default, 'table_cloth/presenters/default'
16
+ autoload :Default, "table_cloth/presenters/default"
18
17
  end
19
18
 
20
- module Columns
21
- autoload :Action, 'table_cloth/columns/action'
19
+ module Extensions
20
+ autoload :Actions, "table_cloth/extensions/actions"
22
21
  end
23
22
 
24
23
  def config_for(type)
@@ -11,16 +11,6 @@ module TableCloth
11
11
  @view = view
12
12
  end
13
13
 
14
- def columns
15
- @columns ||= self.class.columns.each_with_object({}) do |(column_name, column), columns|
16
- columns[column_name] = column if column.available?(self)
17
- end
18
- end
19
-
20
- def has_actions?
21
- self.class.has_actions?
22
- end
23
-
24
14
  class << self
25
15
  def presenter(klass=nil)
26
16
  return @presenter = klass if klass
@@ -40,7 +30,7 @@ module TableCloth
40
30
  column_class = options.delete(:using) || Column
41
31
 
42
32
  args.each do |name|
43
- add_column name, column_class.new(name, options)
33
+ add_column(class: column_class, options: options, name: name)
44
34
  end
45
35
  end
46
36
 
@@ -53,22 +43,9 @@ module TableCloth
53
43
  @columns
54
44
  end
55
45
 
56
- def add_column(name, column)
46
+ def add_column(options)
57
47
  @columns ||= {}
58
- @columns[name] = column
59
- end
60
-
61
- def actions(options={}, &block)
62
- if block_given?
63
- actions = Actions.new(options, &block)
64
- columns[:actions] = actions.column
65
- end
66
-
67
- columns[:actions].actions
68
- end
69
-
70
- def has_actions?
71
- columns[:actions].present?
48
+ @columns[options[:name]] = options
72
49
  end
73
50
  end
74
51
  end
@@ -18,17 +18,5 @@ module TableCloth
18
18
  def human_name
19
19
  options[:label] || name.to_s.humanize
20
20
  end
21
-
22
- def available?(table)
23
- if options[:if] && options[:if].is_a?(Symbol)
24
- return !!table.send(options[:if])
25
- end
26
-
27
- if options[:unless] && options[:unless].is_a?(Symbol)
28
- return !table.send(options[:unless])
29
- end
30
-
31
- true
32
- end
33
21
  end
34
22
  end
@@ -1,12 +1,12 @@
1
1
  module TableCloth
2
- class Action
3
- attr_reader :action, :options
4
-
5
- def initialize(options)
6
- @options = options
2
+ class ColumnJury
3
+ attr_reader :column, :table
4
+
5
+ def initialize(column, table)
6
+ @column, @table = column, table
7
7
  end
8
8
 
9
- def available?(table)
9
+ def available?
10
10
  if options[:if] && options[:if].is_a?(Symbol)
11
11
  return !!table.send(options[:if])
12
12
  end
@@ -17,5 +17,9 @@ module TableCloth
17
17
 
18
18
  true
19
19
  end
20
+
21
+ def options
22
+ column.options
23
+ end
20
24
  end
21
25
  end
@@ -1,21 +1,14 @@
1
1
  module TableCloth
2
2
  module ConfigurableElements
3
+ OPTIONS = %w(table thead th tbody tr td).map(&:to_sym)
4
+
3
5
  extend ActiveSupport::Concern
4
6
 
5
7
  included do
6
- cattr_accessor :table
7
- cattr_accessor :thead
8
- cattr_accessor :th
9
- cattr_accessor :tbody
10
- cattr_accessor :tr
11
- cattr_accessor :td
12
-
13
- self.table = ActiveSupport::OrderedOptions.new
14
- self.thead = ActiveSupport::OrderedOptions.new
15
- self.th = ActiveSupport::OrderedOptions.new
16
- self.tbody = ActiveSupport::OrderedOptions.new
17
- self.tr = ActiveSupport::OrderedOptions.new
18
- self.td = ActiveSupport::OrderedOptions.new
8
+ OPTIONS.each do |option|
9
+ cattr_accessor option
10
+ self.send "#{option}=", ActiveSupport::OrderedOptions.new
11
+ end
19
12
  end
20
13
  end
21
14
  end
@@ -0,0 +1,25 @@
1
+ module TableCloth
2
+ module Extensions
3
+ module Actions
4
+ autoload :Action, "table_cloth/extensions/actions/action"
5
+ autoload :Column, "table_cloth/extensions/actions/column"
6
+ autoload :ActionCollection, "table_cloth/extensions/actions/action_collection"
7
+ autoload :Jury, "table_cloth/extensions/actions/jury"
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ def actions(options={}, &block)
12
+ action_collection.instance_eval(&block)
13
+
14
+ column :actions, options.update(collection: action_collection, using: Column)
15
+ end
16
+
17
+ private
18
+
19
+ def action_collection
20
+ @action_collection ||= ActionCollection.new
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ module TableCloth::Extensions::Actions
2
+ class Action
3
+ attr_reader :options
4
+
5
+ def initialize(options={})
6
+ @options = options
7
+ end
8
+
9
+ def jury
10
+ @jury ||= Jury.new(self)
11
+ end
12
+
13
+ def value(object, view)
14
+ if jury.available?(object)
15
+ view.instance_exec(object, &options[:proc])
16
+ else
17
+ ""
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module TableCloth::Extensions::Actions
2
+ class ActionCollection
3
+ def actions
4
+ @actions ||= []
5
+ end
6
+
7
+ def action(options={}, &block)
8
+ actions << Action.new({proc: block}.merge(options))
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module TableCloth::Extensions::Actions
2
+ class Column < ::TableCloth::Column
3
+ def value(object, view, table=nil)
4
+ actions = action_collection.actions.map do |action|
5
+ action.value(object, view)
6
+ end
7
+
8
+ view.raw(actions.join(separator))
9
+ end
10
+
11
+ private
12
+
13
+ def separator
14
+ options[:separator] || " "
15
+ end
16
+
17
+ def action_collection
18
+ @action_collection ||= options[:collection]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ module TableCloth::Extensions::Actions
2
+ class Jury
3
+ attr_reader :action
4
+
5
+ def initialize(action)
6
+ @action = action
7
+ end
8
+
9
+ def available?(object)
10
+ case action_if
11
+ when Proc
12
+ return !!action_if.call(object)
13
+ when Symbol
14
+ return !!object.send(action_if)
15
+ end
16
+
17
+ case action_unless
18
+ when Proc
19
+ return !action_unless.call(object)
20
+ when Symbol
21
+ return !object.send(action_unless)
22
+ end
23
+
24
+ return true
25
+ end
26
+
27
+ private
28
+
29
+ def action_if
30
+ action.options[:if]
31
+ end
32
+
33
+ def action_unless
34
+ action.options[:unless]
35
+ end
36
+ end
37
+ end
@@ -4,13 +4,12 @@ module TableCloth
4
4
  :table
5
5
 
6
6
  def initialize(objects, table, view)
7
- @view_context = view
8
- @table_definition = table
9
7
  @objects = objects
8
+ @table_definition = table
9
+ @view_context = view
10
10
  @table = table_definition.new(objects, view)
11
11
  end
12
12
 
13
- # Short hand so your fingers don't hurt
14
13
  def v
15
14
  view_context
16
15
  end
@@ -27,14 +26,26 @@ module TableCloth
27
26
  raise NoMethodError, "You must override the .rows method"
28
27
  end
29
28
 
29
+ def columns
30
+ @columns ||= table.class.columns.map do |name, options|
31
+ column = options[:class].new(name, options[:options])
32
+
33
+ if ColumnJury.new(column, table).available?
34
+ column
35
+ else
36
+ nil
37
+ end
38
+ end.compact
39
+ end
40
+
30
41
  def column_names
31
- @column_names ||= table.columns.each_with_object([]) do |(column_name, column), names|
42
+ @column_names ||= columns.each_with_object([]) do |column, names|
32
43
  names << column.human_name
33
44
  end
34
45
  end
35
46
 
36
47
  def row_values(object)
37
- table.columns.each_with_object([]) do |(key, column), values|
48
+ columns.each_with_object([]) do |column, values|
38
49
  values << column.value(object, view_context, table)
39
50
  end
40
51
  end
@@ -15,7 +15,7 @@ module TableCloth
15
15
 
16
16
  def render_row(object)
17
17
  wrapper_tag :tr do
18
- v.raw table.columns.inject('') {|tds, (key, column)| tds + render_td(column, object) }
18
+ v.raw columns.inject('') {|tds, column| tds + render_td(column, object) }
19
19
  end
20
20
  end
21
21
 
@@ -1,3 +1,3 @@
1
1
  module TableCloth
2
- VERSION = "0.2.3"
2
+ VERSION = "0.3.0.beta1"
3
3
  end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :action, class: "TableCloth::Extensions::Actions::Action" do
3
+ options({})
4
+ initialize_with { new(options) }
5
+ end
6
+ end
@@ -0,0 +1,18 @@
1
+ FactoryGirl.define do
2
+ factory :column, class: "TableCloth::Column" do
3
+ name :name
4
+ options({})
5
+
6
+ factory :if_column do
7
+ name :name
8
+ options({ if: :admin? })
9
+ end
10
+
11
+ factory :unless_column do
12
+ name :name
13
+ options({ unless: :moderator? })
14
+ end
15
+
16
+ initialize_with { new(name, options) }
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ FactoryGirl.define do
2
+ factory :dummy_table, class: "TableCloth::Base" do
3
+ initialize_with do
4
+ Class.new(TableCloth::Base).tap do |klass|
5
+ attributes.each do |key,attribute|
6
+ klass.column *[key, attribute]
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -16,7 +16,8 @@ describe TableCloth::Base do
16
16
  end
17
17
 
18
18
  it 'column accepts options' do
19
- expect { subject.column :n, {option: 'value'} }.not_to raise_error
19
+ subject.column :name, option: "value"
20
+ expect(subject.columns[:name][:options][:option]).to eq("value")
20
21
  end
21
22
 
22
23
  it '.columns returns all columns' do
@@ -33,22 +34,16 @@ describe TableCloth::Base do
33
34
  subject.column(:name) { 'Wee' }
34
35
 
35
36
  column = subject.columns[:name]
36
- expect(column.options[:proc]).to be_present
37
- expect(column.options[:proc]).to be_kind_of(Proc)
37
+ expect(column[:options][:proc]).to be_present
38
+ expect(column[:options][:proc]).to be_kind_of(Proc)
38
39
  end
39
40
 
40
41
  context "custom" do
41
- let(:custom_column) do
42
- Class.new(TableCloth::Column) do
43
- def value(object, view)
44
- "AN EMAIL!"
45
- end
46
- end
47
- end
42
+ let(:custom_column) { stub(:custom, value: "AN EMAIL") }
48
43
 
49
44
  it '.column can take a custom column' do
50
45
  subject.column :email, using: custom_column
51
- subject.columns[:email].value(dummy_model, view_context).should == "AN EMAIL!"
46
+ expect(subject.columns[:email][:class]).to eq(custom_column)
52
47
  end
53
48
  end
54
49
  end
@@ -59,17 +54,6 @@ describe TableCloth::Base do
59
54
  end
60
55
  end
61
56
 
62
- context 'actions' do
63
- it "takes a block" do
64
- subject.actions do
65
- action { 'Edit' }
66
- action { 'Delete' }
67
- end
68
-
69
- expect(subject.columns[:actions]).to be_kind_of TableCloth::Columns::Action
70
- end
71
- end
72
-
73
57
  context "configuration" do
74
58
  subject { Class.new(TableCloth::Base) }
75
59
  let(:sibling1_class) { Class.new(subject) }