greedo 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +87 -0
  7. data/Rakefile +2 -0
  8. data/app/views/greedo/_grid.html.haml +28 -0
  9. data/greedo.gemspec +32 -0
  10. data/lib/greedo.rb +15 -0
  11. data/lib/greedo/engine.rb +4 -0
  12. data/lib/greedo/grid_helper.rb +180 -0
  13. data/lib/greedo/paginator.rb +61 -0
  14. data/lib/greedo/railtie.rb +7 -0
  15. data/lib/greedo/version.rb +3 -0
  16. data/spec/dummy/README.rdoc +28 -0
  17. data/spec/dummy/Rakefile +6 -0
  18. data/spec/dummy/app/assets/images/.keep +0 -0
  19. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  20. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  21. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  22. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  23. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  24. data/spec/dummy/app/mailers/.keep +0 -0
  25. data/spec/dummy/app/models/.keep +0 -0
  26. data/spec/dummy/app/models/concerns/.keep +0 -0
  27. data/spec/dummy/app/models/project.rb +2 -0
  28. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  29. data/spec/dummy/bin/bundle +3 -0
  30. data/spec/dummy/bin/rails +4 -0
  31. data/spec/dummy/bin/rake +4 -0
  32. data/spec/dummy/bin/setup +29 -0
  33. data/spec/dummy/config.ru +4 -0
  34. data/spec/dummy/config/application.rb +32 -0
  35. data/spec/dummy/config/boot.rb +5 -0
  36. data/spec/dummy/config/database.yml +25 -0
  37. data/spec/dummy/config/environment.rb +5 -0
  38. data/spec/dummy/config/environments/development.rb +41 -0
  39. data/spec/dummy/config/environments/production.rb +79 -0
  40. data/spec/dummy/config/environments/test.rb +42 -0
  41. data/spec/dummy/config/initializers/assets.rb +11 -0
  42. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  43. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  44. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  45. data/spec/dummy/config/initializers/inflections.rb +16 -0
  46. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  47. data/spec/dummy/config/initializers/session_store.rb +3 -0
  48. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  49. data/spec/dummy/config/locales/en.yml +23 -0
  50. data/spec/dummy/config/routes.rb +57 -0
  51. data/spec/dummy/config/secrets.yml +22 -0
  52. data/spec/dummy/db/development.sqlite3 +0 -0
  53. data/spec/dummy/db/migrate/20150918151106_create_projects.rb +9 -0
  54. data/spec/dummy/db/schema.rb +23 -0
  55. data/spec/dummy/db/test.sqlite3 +0 -0
  56. data/spec/dummy/lib/assets/.keep +0 -0
  57. data/spec/dummy/public/404.html +67 -0
  58. data/spec/dummy/public/422.html +67 -0
  59. data/spec/dummy/public/500.html +66 -0
  60. data/spec/dummy/public/favicon.ico +0 -0
  61. data/spec/greedo/grid_helper_spec.rb +161 -0
  62. data/spec/spec_helper.rb +14 -0
  63. metadata +294 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 41e6db7010b9c6b8f6ae92d169ed8ae92ed39ab6dae893b3b8329e9607c66b4f
4
+ data.tar.gz: '082944928cb20ae268e60aa2e8a4b7c43d18fb50035d35093935dba9a558f042'
5
+ SHA512:
6
+ metadata.gz: 792af4f3c7d45b7d371a49c08dfc411dc0d212366fe6851d85139e9d71a28fd02dd9fe9532c27275d84ef7ad5828a4248243fb62506b575b319c3914f09626c6
7
+ data.tar.gz: df4db7d6e7cd53ab6cee2144284f61e3be1e65f1bf23cf96f886fff5a32220ca867185c2e7919425be4b367850924b687250203648302d05131624b3fdd1145d
@@ -0,0 +1,25 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .ruby-gemset
24
+ .ruby-version
25
+ spec/dummy/log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in greedo.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Adam Pohorecki
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,87 @@
1
+ # Greedo
2
+
3
+ A very simple helper for generating data tables.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'greedo'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install greedo
18
+
19
+ ## Usage
20
+
21
+ After installing greedo, you can use the helper like this:
22
+
23
+ ```haml
24
+ %h1 My first table
25
+
26
+ = greedo(User.registered, per_page: 10) do |g|
27
+ = g.column :name
28
+ = g.column "Actions" do |user|
29
+ = link_to "Edit", edit_user_path(user)
30
+ ```
31
+
32
+ This will create a data table with two columns, one labelled "Name" and the other "Actions".
33
+ It will show 10 users from the given scope (which should either be an ActiveRecord::Relation or an Array).
34
+ Pagination will be added if necessary.
35
+
36
+ ### Custom empty message
37
+
38
+ ```haml
39
+ %h1 My first table
40
+
41
+ = greedo(User.registered, per_page: 10) do |g|
42
+ = g.custom_empty_message "There are no users in the database."
43
+ = g.column :name
44
+ ```
45
+
46
+ ### Presenters
47
+
48
+ You can wrap records in a class instance:
49
+
50
+ ```haml
51
+ %h1 Table with class presenters
52
+
53
+ = greedo(User.registered) do |g|
54
+ = g.presenter UserPresenter
55
+ = g.column :manager_name
56
+ ```
57
+
58
+ or the same with a block:
59
+
60
+ ```haml
61
+ %h1 Table with class presenters
62
+
63
+ = greedo(User.registered) do |g|
64
+ - g.presenter do |record|
65
+ UserPresenter.new(record)
66
+ = g.column :manager_name
67
+ ```
68
+
69
+ ## Limitations
70
+
71
+ This is a very simple helper for now - there's no sorting, or even any way to easily customize the generated HTML. This will change in time, but for now I'm open-sourcing this mainly to share this useful bit of code between projects.
72
+
73
+ ## TODO:
74
+
75
+ Here's a couple of things I'm planning to add to this gem:
76
+
77
+ * sorting by clicking on a column name
78
+ * a generator to install the templates used by greedo in your project for ease of customization
79
+ * making the paginator library swappable (greedo uses will_paginate now).
80
+
81
+ ## Contributing
82
+
83
+ 1. Fork it ( https://github.com/[my-github-username]/greedo/fork )
84
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
85
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
86
+ 4. Push to the branch (`git push origin my-new-feature`)
87
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,28 @@
1
+ - if grid.empty?
2
+ = grid.empty_message
3
+ - else
4
+ %table.table.table-striped
5
+ %thead
6
+ %tr
7
+ - grid.headers.each do |header|
8
+ %th{class: header.klass}
9
+ .greedo-header
10
+ = header.label
11
+ - if header.sort
12
+ .greedo-order
13
+ = link_to header.order_asc_path do
14
+ %i.glyphicon{class: header.order_asc_class}
15
+ = link_to header.order_desc_path do
16
+ %i.glyphicon{class: header.order_desc_class}
17
+
18
+ %tbody
19
+ - grid.rows.each do |row|
20
+ %tr{id: row.id}
21
+ - row.columns.each do |column|
22
+ %td{class: column.klass}
23
+ = column.value
24
+
25
+ - if grid.show_pagination?
26
+ = will_paginate grid.paginator.records, param_name: param_name,
27
+ params: path_params,
28
+ renderer: BootstrapPagination::Rails
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'greedo/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "greedo"
8
+ spec.version = Greedo::VERSION
9
+ spec.authors = ["Adam Pohorecki"]
10
+ spec.email = ["adam@pohorecki.pl"]
11
+ spec.summary = %q{A very simple grid library}
12
+ spec.description = %q{Shortens the syntax for creating tables}
13
+ spec.homepage = "https://github.com/gunpowderlabs/greedo"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec-core"
24
+ spec.add_development_dependency "rspec-rails"
25
+ spec.add_development_dependency "capybara"
26
+ spec.add_development_dependency "rails", "~> 4.2"
27
+ spec.add_development_dependency "sqlite3"
28
+
29
+ spec.add_dependency "haml"
30
+ spec.add_dependency "will_paginate"
31
+ spec.add_dependency "will_paginate-bootstrap"
32
+ end
@@ -0,0 +1,15 @@
1
+ require "haml"
2
+
3
+ require "greedo/version"
4
+ require "greedo/grid_helper"
5
+ require "greedo/paginator"
6
+ require "greedo/railtie"
7
+ require "greedo/engine"
8
+
9
+ module Greedo
10
+ def self.init
11
+ ActiveSupport.on_load(:action_view) do
12
+ ::ActionView::Base.send :include, Greedo::GridHelper
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ module Greedo
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,180 @@
1
+ module Greedo
2
+ module GridHelper
3
+ class Grid
4
+ attr_accessor :paginator
5
+ attr_reader :view_context, :fields, :presenter, :empty_message_text,
6
+ :order, :order_by, :path_params
7
+
8
+ def initialize(view_context:, order: nil, order_by: nil, path_params: nil)
9
+ @view_context = view_context
10
+ @row_id = ->(record) { default_row_id(record) }
11
+ @fields = []
12
+ @presenter = proc{|r| r}
13
+ @empty_message_text = "No data to show."
14
+ @order = order
15
+ @order_by = order_by
16
+ @path_params = path_params
17
+ end
18
+
19
+ def configure
20
+ yield self if block_given?
21
+ end
22
+
23
+ def custom_empty_message(empty_message_text)
24
+ @empty_message_text = empty_message_text
25
+ nil
26
+ end
27
+
28
+ def ordered_by
29
+ fields.find(&:ordered_by?) || Field.new
30
+ end
31
+
32
+ def row_id(&block)
33
+ @row_id = block
34
+ nil
35
+ end
36
+
37
+ def column(name, label: name.to_s.humanize, sort: nil, &block)
38
+ if sort.nil? && name.is_a?(Symbol)
39
+ sort = name.to_s
40
+ end
41
+ if block
42
+ renderer = ->(record) { view_context.capture(present(record), &block) }
43
+ else
44
+ renderer = ->(record) { present(record).public_send(name) }
45
+ end
46
+
47
+ fields << Field.new(name, label, renderer, order, order_by, view_context, sort, path_params)
48
+ nil
49
+ end
50
+
51
+ def presenter(klass = nil, &block)
52
+ block = proc{|r| klass.new(r)} if klass
53
+ @presenter = block
54
+ nil
55
+ end
56
+
57
+ def present(record)
58
+ @presenter.call(record)
59
+ end
60
+
61
+ def rows
62
+ records.map do |record|
63
+ Row.new(record, @row_id, fields)
64
+ end
65
+ end
66
+
67
+ def headers
68
+ fields
69
+ end
70
+
71
+ def empty?
72
+ records.empty?
73
+ end
74
+
75
+ def show_pagination?
76
+ paginator.show?
77
+ end
78
+
79
+ def empty_message
80
+ view_context.content_tag(:p) { empty_message_text }
81
+ end
82
+
83
+ private
84
+
85
+ def records
86
+ paginator.records
87
+ end
88
+
89
+ def default_row_id(record)
90
+ snake_class = record.class.name.underscore.gsub("_", "-")
91
+ "#{snake_class}-#{record.id}"
92
+ end
93
+
94
+ Column = Struct.new(:value, :klass)
95
+
96
+ Row = Struct.new(:record, :row_id, :fields) do
97
+ def id
98
+ row_id.call(record)
99
+ end
100
+
101
+ def columns
102
+ fields.map{ |f| Column.new(f.value(record), f.klass) }
103
+ end
104
+ end
105
+
106
+ Field = Struct.new(:name, :label, :renderer, :order, :order_by,
107
+ :view_context, :sort, :path_params) do
108
+ def value(record)
109
+ renderer.call(record)
110
+ end
111
+
112
+ def klass
113
+ label.parameterize.underscore
114
+ end
115
+
116
+ def ordered_by?
117
+ order_by == name.to_s && %w(asc desc).include?(order)
118
+ end
119
+
120
+ def params
121
+ view_context.params.merge(path_params)
122
+ end
123
+
124
+ def order_desc_path
125
+ if ordered_by? && order == "desc"
126
+ view_context.url_for(params.merge(order: nil, order_by: nil))
127
+ else
128
+ view_context.url_for(params.merge(order: :desc, order_by: name))
129
+ end
130
+ end
131
+
132
+ def order_asc_path
133
+ if ordered_by? && order == "asc"
134
+ view_context.url_for(params.merge(order: nil, order_by: nil))
135
+ else
136
+ view_context.url_for(params.merge(order: :asc, order_by: name))
137
+ end
138
+ end
139
+
140
+ def order_desc_class
141
+ if ordered_by? && order == "desc"
142
+ "glyphicon-triangle-bottom"
143
+ else
144
+ "glyphicon-chevron-down"
145
+ end
146
+ end
147
+
148
+ def order_asc_class
149
+ if ordered_by? && order == "asc"
150
+ "glyphicon-triangle-top"
151
+ else
152
+ "glyphicon-chevron-up"
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ def greedo(scope,
159
+ param_name: :page,
160
+ page: params.fetch(param_name) { 1 }.to_i,
161
+ per_page: nil,
162
+ path_params: {},
163
+ order: params[:order],
164
+ order_by: params[:order_by],
165
+ &block)
166
+ grid = Grid.new(view_context: self,
167
+ order: order,
168
+ order_by: order_by,
169
+ path_params: path_params)
170
+ grid.configure(&block)
171
+ grid.paginator = Paginator.build(scope,
172
+ page: page,
173
+ per_page: (params[:per_page] || per_page || 20).to_i,
174
+ order_by: grid.ordered_by)
175
+ render partial: "greedo/grid", locals: {grid: grid,
176
+ param_name: param_name,
177
+ path_params: path_params}
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,61 @@
1
+ require "will_paginate"
2
+ require "will_paginate-bootstrap"
3
+
4
+ module Greedo
5
+ class Paginator
6
+ attr_reader :scope, :page, :per_page, :order, :order_by
7
+
8
+ def self.build(scope,
9
+ page: 1,
10
+ per_page: 20,
11
+ order_by: nil)
12
+ return ArrayPaginator.new(scope, order_by.order, order_by.sort) if scope.is_a?(Array)
13
+ Paginator.new(scope, page: page, per_page: per_page,
14
+ order: order_by.order, order_by: order_by.sort)
15
+ end
16
+
17
+ def initialize(scope, page:, per_page:, order: nil, order_by: nil)
18
+ @scope = scope
19
+ @page = page
20
+ @per_page = per_page
21
+ @order = order
22
+ @order_by = order_by
23
+ end
24
+
25
+ def records
26
+ paginated = scope.paginate(page: page, per_page: per_page)
27
+ order_by_fields = [order_by].flatten.map { |field| "#{field} #{order}" }.join(", ")
28
+ order_by ? paginated.reorder(order_by_fields) : paginated
29
+ end
30
+
31
+ def show?
32
+ scope.length > per_page
33
+ end
34
+ end
35
+
36
+ class ArrayPaginator
37
+ attr_reader :order, :order_by
38
+
39
+ def initialize(records, order, order_by)
40
+ @records = records
41
+ @order = order
42
+ @order_by = order_by
43
+ end
44
+
45
+ def records
46
+ @sorted_records ||= sort_records
47
+ end
48
+
49
+ def show?
50
+ false
51
+ end
52
+
53
+ private
54
+
55
+ def sort_records
56
+ sorted = order_by ? @records.sort_by { |r| r.send(order_by) } : @records
57
+
58
+ order == "desc" ? sorted.reverse : sorted
59
+ end
60
+ end
61
+ end