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.
- data/.gitignore +1 -0
- data/lib/generators/templates/table.rb +7 -0
- data/lib/table_cloth.rb +14 -15
- data/lib/table_cloth/base.rb +3 -26
- data/lib/table_cloth/column.rb +0 -12
- data/lib/table_cloth/{action.rb → column_jury.rb} +10 -6
- data/lib/table_cloth/configurable_elements.rb +6 -13
- data/lib/table_cloth/extensions/actions.rb +25 -0
- data/lib/table_cloth/extensions/actions/action.rb +21 -0
- data/lib/table_cloth/extensions/actions/action_collection.rb +11 -0
- data/lib/table_cloth/extensions/actions/column.rb +21 -0
- data/lib/table_cloth/extensions/actions/jury.rb +37 -0
- data/lib/table_cloth/presenter.rb +16 -5
- data/lib/table_cloth/presenters/default.rb +1 -1
- data/lib/table_cloth/version.rb +1 -1
- data/spec/factories/actions.rb +6 -0
- data/spec/factories/columns.rb +18 -0
- data/spec/factories/dummy_tables.rb +11 -0
- data/spec/lib/base_spec.rb +6 -22
- data/spec/lib/column_jury_spec.rb +35 -0
- data/spec/lib/column_spec.rb +9 -14
- data/spec/lib/extensions/actions/action_collection_spec.rb +29 -0
- data/spec/lib/extensions/actions/action_spec.rb +57 -0
- data/spec/lib/extensions/actions/column_spec.rb +23 -0
- data/spec/lib/extensions/actions/jury_spec.rb +67 -0
- data/spec/lib/extensions/actions_spec.rb +42 -0
- data/spec/lib/presenter_spec.rb +29 -31
- data/spec/lib/presenters/default_spec.rb +61 -124
- data/spec/spec_helper.rb +7 -0
- data/spec/support/dummy_table.rb +0 -4
- data/spec/support/dummy_table_with_value_options.rb +1 -1
- data/spec/support/matchers/element_matchers.rb +6 -0
- data/table_cloth.gemspec +2 -0
- metadata +63 -14
- data/lib/table_cloth/actions.rb +0 -23
- data/lib/table_cloth/columns/action.rb +0 -24
- data/spec/lib/actions_spec.rb +0 -28
- data/spec/lib/columns/action_spec.rb +0 -73
- data/spec/support/dummy_table_with_actions.rb +0 -7
data/.gitignore
CHANGED
@@ -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
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
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,
|
9
|
-
autoload :Builder,
|
10
|
-
autoload :Column,
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
autoload :
|
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,
|
16
|
+
autoload :Default, "table_cloth/presenters/default"
|
18
17
|
end
|
19
18
|
|
20
|
-
module
|
21
|
-
autoload :
|
19
|
+
module Extensions
|
20
|
+
autoload :Actions, "table_cloth/extensions/actions"
|
22
21
|
end
|
23
22
|
|
24
23
|
def config_for(type)
|
data/lib/table_cloth/base.rb
CHANGED
@@ -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
|
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(
|
46
|
+
def add_column(options)
|
57
47
|
@columns ||= {}
|
58
|
-
@columns[name] =
|
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
|
data/lib/table_cloth/column.rb
CHANGED
@@ -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
|
3
|
-
attr_reader :
|
4
|
-
|
5
|
-
def initialize(
|
6
|
-
@
|
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?
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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,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 ||=
|
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
|
-
|
48
|
+
columns.each_with_object([]) do |column, values|
|
38
49
|
values << column.value(object, view_context, table)
|
39
50
|
end
|
40
51
|
end
|
data/lib/table_cloth/version.rb
CHANGED
@@ -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
|
data/spec/lib/base_spec.rb
CHANGED
@@ -16,7 +16,8 @@ describe TableCloth::Base do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'column accepts options' do
|
19
|
-
|
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
|
37
|
-
expect(column
|
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)
|
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].
|
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) }
|