active_reporter 0.5.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +14 -0
  3. data/README.md +436 -0
  4. data/Rakefile +23 -0
  5. data/lib/active_reporter.rb +26 -0
  6. data/lib/active_reporter/aggregator.rb +9 -0
  7. data/lib/active_reporter/aggregator/array.rb +14 -0
  8. data/lib/active_reporter/aggregator/average.rb +9 -0
  9. data/lib/active_reporter/aggregator/base.rb +73 -0
  10. data/lib/active_reporter/aggregator/count.rb +23 -0
  11. data/lib/active_reporter/aggregator/count_if.rb +23 -0
  12. data/lib/active_reporter/aggregator/max.rb +9 -0
  13. data/lib/active_reporter/aggregator/min.rb +9 -0
  14. data/lib/active_reporter/aggregator/ratio.rb +23 -0
  15. data/lib/active_reporter/aggregator/sum.rb +13 -0
  16. data/lib/active_reporter/calculator.rb +2 -0
  17. data/lib/active_reporter/calculator/base.rb +19 -0
  18. data/lib/active_reporter/calculator/ratio.rb +9 -0
  19. data/lib/active_reporter/dimension.rb +8 -0
  20. data/lib/active_reporter/dimension/base.rb +150 -0
  21. data/lib/active_reporter/dimension/bin.rb +123 -0
  22. data/lib/active_reporter/dimension/bin/set.rb +162 -0
  23. data/lib/active_reporter/dimension/bin/table.rb +43 -0
  24. data/lib/active_reporter/dimension/category.rb +29 -0
  25. data/lib/active_reporter/dimension/enum.rb +32 -0
  26. data/lib/active_reporter/dimension/number.rb +51 -0
  27. data/lib/active_reporter/dimension/time.rb +93 -0
  28. data/lib/active_reporter/evaluator.rb +2 -0
  29. data/lib/active_reporter/evaluator/base.rb +17 -0
  30. data/lib/active_reporter/evaluator/block.rb +15 -0
  31. data/lib/active_reporter/inflector.rb +8 -0
  32. data/lib/active_reporter/invalid_params_error.rb +4 -0
  33. data/lib/active_reporter/report.rb +102 -0
  34. data/lib/active_reporter/report/aggregation.rb +297 -0
  35. data/lib/active_reporter/report/definition.rb +195 -0
  36. data/lib/active_reporter/report/metrics.rb +75 -0
  37. data/lib/active_reporter/report/validation.rb +106 -0
  38. data/lib/active_reporter/serializer.rb +7 -0
  39. data/lib/active_reporter/serializer/base.rb +103 -0
  40. data/lib/active_reporter/serializer/csv.rb +22 -0
  41. data/lib/active_reporter/serializer/form_field.rb +134 -0
  42. data/lib/active_reporter/serializer/hash_table.rb +12 -0
  43. data/lib/active_reporter/serializer/highcharts.rb +200 -0
  44. data/lib/active_reporter/serializer/nested_hash.rb +11 -0
  45. data/lib/active_reporter/serializer/table.rb +21 -0
  46. data/lib/active_reporter/tracker.rb +2 -0
  47. data/lib/active_reporter/tracker/base.rb +15 -0
  48. data/lib/active_reporter/tracker/delta.rb +9 -0
  49. data/lib/active_reporter/version.rb +3 -0
  50. data/lib/tasks/active_reporter_tasks.rake +4 -0
  51. data/spec/acceptance/data_spec.rb +381 -0
  52. data/spec/active_reporter/aggregator_spec.rb +102 -0
  53. data/spec/active_reporter/dimension/base_spec.rb +102 -0
  54. data/spec/active_reporter/dimension/bin/set_spec.rb +83 -0
  55. data/spec/active_reporter/dimension/bin/table_spec.rb +47 -0
  56. data/spec/active_reporter/dimension/bin_spec.rb +77 -0
  57. data/spec/active_reporter/dimension/category_spec.rb +60 -0
  58. data/spec/active_reporter/dimension/enum_spec.rb +94 -0
  59. data/spec/active_reporter/dimension/number_spec.rb +71 -0
  60. data/spec/active_reporter/dimension/time_spec.rb +61 -0
  61. data/spec/active_reporter/report_spec.rb +597 -0
  62. data/spec/active_reporter/serializer/hash_table_spec.rb +45 -0
  63. data/spec/active_reporter/serializer/highcharts_spec.rb +113 -0
  64. data/spec/active_reporter/serializer/table_spec.rb +62 -0
  65. data/spec/dummy/README.rdoc +28 -0
  66. data/spec/dummy/Rakefile +6 -0
  67. data/spec/dummy/app/assets/config/manifest.js +0 -0
  68. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  69. data/spec/dummy/app/assets/stylesheets/application.css +26 -0
  70. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  71. data/spec/dummy/app/controllers/site_controller.rb +11 -0
  72. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  73. data/spec/dummy/app/models/author.rb +4 -0
  74. data/spec/dummy/app/models/comment.rb +4 -0
  75. data/spec/dummy/app/models/data_builder.rb +112 -0
  76. data/spec/dummy/app/models/post.rb +6 -0
  77. data/spec/dummy/app/models/post_report.rb +14 -0
  78. data/spec/dummy/app/views/layouts/application.html.erb +17 -0
  79. data/spec/dummy/app/views/site/report.html.erb +73 -0
  80. data/spec/dummy/bin/bundle +3 -0
  81. data/spec/dummy/bin/rails +4 -0
  82. data/spec/dummy/bin/rake +4 -0
  83. data/spec/dummy/bin/setup +29 -0
  84. data/spec/dummy/config.ru +4 -0
  85. data/spec/dummy/config/application.rb +26 -0
  86. data/spec/dummy/config/boot.rb +5 -0
  87. data/spec/dummy/config/database.yml +22 -0
  88. data/spec/dummy/config/environment.rb +5 -0
  89. data/spec/dummy/config/environments/development.rb +41 -0
  90. data/spec/dummy/config/environments/production.rb +79 -0
  91. data/spec/dummy/config/environments/test.rb +42 -0
  92. data/spec/dummy/config/initializers/assets.rb +11 -0
  93. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  94. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  95. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  96. data/spec/dummy/config/initializers/inflections.rb +16 -0
  97. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  98. data/spec/dummy/config/initializers/session_store.rb +3 -0
  99. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  100. data/spec/dummy/config/locales/en.yml +23 -0
  101. data/spec/dummy/config/routes.rb +57 -0
  102. data/spec/dummy/config/secrets.yml +22 -0
  103. data/spec/dummy/db/migrate/20150714202319_add_dummy_models.rb +25 -0
  104. data/spec/dummy/db/schema.rb +43 -0
  105. data/spec/dummy/db/seeds.rb +1 -0
  106. data/spec/dummy/log/test.log +37033 -0
  107. data/spec/dummy/public/404.html +67 -0
  108. data/spec/dummy/public/422.html +67 -0
  109. data/spec/dummy/public/500.html +66 -0
  110. data/spec/dummy/public/favicon.ico +0 -0
  111. data/spec/factories/factories.rb +29 -0
  112. data/spec/spec_helper.rb +40 -0
  113. data/spec/support/float.rb +8 -0
  114. metadata +385 -0
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveReporter::Serializer::HashTable do
4
+ let(:report_model) do
5
+ Class.new(ActiveReporter::Report) do
6
+ report_on :Post
7
+ number_dimension :likes
8
+ time_dimension :created_at
9
+ category_dimension :title
10
+ count_aggregator :post_count
11
+ sum_aggregator :likes_count, attribute: :likes
12
+ end
13
+ end
14
+
15
+ let(:report) do
16
+ report_model.new(
17
+ aggregators: [:post_count, :likes_count],
18
+ groupers: %i[title created_at],
19
+ dimensions: { created_at: { bin_width: '1 day' } }
20
+ )
21
+ end
22
+
23
+ let(:hash_table) do
24
+ ActiveReporter::Serializer::HashTable.new(report)
25
+ end
26
+
27
+ before do
28
+ create(:post, created_at: '2016-01-01', likes: 2, title: 'A')
29
+ create(:post, created_at: '2016-01-01', likes: 2, title: 'A')
30
+ create(:post, created_at: '2016-01-01', likes: 1, title: 'B')
31
+ create(:post, created_at: '2016-01-02', likes: 1, title: 'A')
32
+ end
33
+
34
+ describe '#report' do
35
+ it 'builds report' do
36
+ expect(hash_table.table).to eq [
37
+ { title: 'Title', created_at: 'Created at', post_count: 'Post count', likes_count: 'Likes count' },
38
+ { title: 'A', created_at: '2016-01-01 00:00:00 UTC', post_count: '2', likes_count: '4' },
39
+ { title: 'A', created_at: '2016-01-02 00:00:00 UTC', post_count: '1', likes_count: '1' },
40
+ { title: 'B', created_at: '2016-01-01 00:00:00 UTC', post_count: '1', likes_count: '1' },
41
+ { title: 'B', created_at: '2016-01-02 00:00:00 UTC', post_count: '0', likes_count: '0' }
42
+ ]
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveReporter::Serializer::Highcharts do
4
+ let(:report_model) do
5
+ Class.new(ActiveReporter::Report) do
6
+ report_on :Post
7
+ number_dimension :likes
8
+ time_dimension :created_at
9
+ category_dimension :title
10
+ count_aggregator :post_count
11
+ end
12
+ end
13
+
14
+ let(:chart) do
15
+ ActiveReporter::Serializer::Highcharts.new(report)
16
+ end
17
+
18
+ before do
19
+ create(:post, created_at: '2016-01-01', likes: 2, title: 'A')
20
+ create(:post, created_at: '2016-01-01', likes: 2, title: 'A')
21
+ create(:post, created_at: '2016-01-01', likes: 1, title: 'B')
22
+ create(:post, created_at: '2016-01-02', likes: 1, title: 'A')
23
+ end
24
+
25
+ def y_values(series)
26
+ series[:data].map { |d| d[:y] }
27
+ end
28
+
29
+ def filters(series)
30
+ series[:data].map { |d| d[:filters] }
31
+ end
32
+
33
+ describe '#series' do
34
+ context 'with one grouper' do
35
+ let(:report) do
36
+ report_model.new(aggregators: :post_count, groupers: %i[title])
37
+ end
38
+
39
+ it 'returns one series of the y values (with filters)' do
40
+ expect(chart.series.count).to eq 1
41
+ # expect(y_values(chart.series[0])).to eq [3, 1]
42
+ expect(filters(chart.series[0])).to eq [{ title: 'A' }, { title: 'B' }]
43
+ end
44
+ end
45
+
46
+ context 'with two groupers' do
47
+ let(:report) do
48
+ report_model.new(
49
+ aggregators: :post_count,
50
+ groupers: %i[title likes],
51
+ dimensions: { likes: { bin_width: 1 } }
52
+ )
53
+ end
54
+
55
+ it 'returns one series for each x_2 value' do
56
+ expect(chart.series.count).to eq 2
57
+ # expect(y_values(chart.series[0])).to eq [1, 1]
58
+ expect(filters(chart.series[0])).to eq [
59
+ { title: 'A', likes: { min: 1, max: 2 } },
60
+ { title: 'B', likes: { min: 1, max: 2 } }
61
+ ]
62
+ # expect(y_values(chart.series[1])).to eq [2, 0]
63
+ expect(filters(chart.series[1])).to eq [
64
+ { title: 'A', likes: { min: 2, max: 3 } },
65
+ { title: 'B', likes: { min: 2, max: 3 } }
66
+ ]
67
+ end
68
+ end
69
+
70
+ context 'with three groupers' do
71
+ let(:report) do
72
+ report_model.new(
73
+ aggregators: :post_count,
74
+ groupers: %i[title likes created_at],
75
+ dimensions: {
76
+ likes: { bin_width: 1 },
77
+ created_at: { bin_width: '1 day' }
78
+ }
79
+ )
80
+ end
81
+
82
+ it 'returns stacks for each x_3 of groups for each x_2' do
83
+ expect(chart.series.count).to eq 4
84
+
85
+ expect(chart.series[0][:stack]).to eq '2016-01-01'
86
+ expect(chart.series[1][:stack]).to eq '2016-01-01'
87
+ expect(chart.series[2][:stack]).to eq '2016-01-02'
88
+ expect(chart.series[3][:stack]).to eq '2016-01-02'
89
+
90
+ expect(chart.series[0][:id]).to eq '[1.0, 2.0)'
91
+ expect(chart.series[1][:id]).to eq '[2.0, 3.0)'
92
+ expect(chart.series[2][:linkedTo]).to eq '[1.0, 2.0)'
93
+ expect(chart.series[3][:linkedTo]).to eq '[2.0, 3.0)'
94
+
95
+ colors = chart.series.map { |s| s[:color] }
96
+ expect(colors.all?(&:present?)).to be true
97
+ expect(colors[0]).to eq colors[2]
98
+ expect(colors[1]).to eq colors[3]
99
+ expect(colors[0]).not_to eq colors[1]
100
+
101
+ # expect(y_values(chart.series[0])).to eq [0, 1]
102
+
103
+ jan1 = Time.zone.parse('2016-01-01')
104
+ jan2 = Time.zone.parse('2016-01-02')
105
+
106
+ expect(filters(chart.series[0])).to eq [
107
+ { title: 'A', likes: { min: 1.0, max: 2.0 }, created_at: { min: jan1, max: jan2 } },
108
+ { title: 'B', likes: { min: 1.0, max: 2.0 }, created_at: { min: jan1, max: jan2 } }
109
+ ]
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveReporter::Serializer::Table do
4
+ let(:report_model) do
5
+ Class.new(ActiveReporter::Report) do
6
+ report_on :Post
7
+ number_dimension :likes
8
+ time_dimension :created_at
9
+ category_dimension :title
10
+ count_aggregator :post_count
11
+ end
12
+ end
13
+
14
+ let(:report) do
15
+ report_model.new(
16
+ aggregators: :post_count,
17
+ groupers: %i[created_at likes title],
18
+ dimensions: {
19
+ created_at: { bin_width: '1 day' },
20
+ likes: { bin_width: 1 }
21
+ }
22
+ )
23
+ end
24
+
25
+ let(:table) do
26
+ ActiveReporter::Serializer::Table.new(report)
27
+ end
28
+
29
+ before do
30
+ create(:post, created_at: '2016-01-01', likes: 2, title: 'A')
31
+ create(:post, created_at: '2016-01-01', likes: 2, title: 'A')
32
+ create(:post, created_at: '2016-01-01', likes: 1, title: 'B')
33
+ create(:post, created_at: '2016-01-02', likes: 1, title: 'A')
34
+ end
35
+
36
+ describe '#headers' do
37
+ it 'is a formatted list of groupers and the aggregator' do
38
+ expect(table.headers).to eq ['Created at', 'Likes', 'Title', 'Post count']
39
+ end
40
+ end
41
+
42
+ describe '#caption' do
43
+ it 'is a summary of the axes and the total record count' do
44
+ expect(table.caption).to eq 'Post count by Created at, Likes, and Title for 4 Posts'
45
+ end
46
+ end
47
+
48
+ describe '#each_row' do
49
+ it 'iterates through arrays of formatted grouper values and the aggregator value' do
50
+ expect(table.each_row.to_a).to eq [
51
+ ['2016-01-01', '[1.0, 2.0)', 'A', 0],
52
+ ['2016-01-01', '[1.0, 2.0)', 'B', 1],
53
+ ['2016-01-01', '[2.0, 3.0)', 'A', 2],
54
+ ['2016-01-01', '[2.0, 3.0)', 'B', 0],
55
+ ['2016-01-02', '[1.0, 2.0)', 'A', 1],
56
+ ['2016-01-02', '[1.0, 2.0)', 'B', 0],
57
+ ['2016-01-02', '[2.0, 3.0)', 'A', 0],
58
+ ['2016-01-02', '[2.0, 3.0)', 'B', 0]
59
+ ]
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,26 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
16
+
17
+ body { margin: 2em; }
18
+ fieldset { display: inline; }
19
+ h2 { margin: 0; }
20
+ form { margin-top: 1em; margin-bottom: 2em; }
21
+ table { width: 100%; }
22
+ select { margin-top: 2px; margin-bottom: 1px; }
23
+ .active-reporter-axis-fields { margin-bottom: 1em; }
24
+ .active-reporter-dimension-fields--number-dimension input { width: 5em; }
25
+ .active-reporter-dimension-fields--time-dimension input { width: 10em; }
26
+ .active-reporter-dimension-fields--time-dimension input:nth-child(4) { width: 5em; }
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,11 @@
1
+ class SiteController < ApplicationController
2
+ def report
3
+ @report = PostReport.new(params.fetch(:post_report, {}))
4
+ @csv = ActiveReporter::Serializer::Csv.new(@report)
5
+
6
+ respond_to do |format|
7
+ format.html
8
+ format.csv { send_data(csv.csv_text, filename: csv.filename) }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,4 @@
1
+ class Author < ActiveRecord::Base
2
+ has_many :posts
3
+ has_many :comments
4
+ end
@@ -0,0 +1,4 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :author
3
+ belongs_to :post
4
+ end
@@ -0,0 +1,112 @@
1
+ class DataBuilder
2
+ class << self
3
+ def gaussian(mean, stddev)
4
+ theta = 2 * Math::PI * Random.new.rand
5
+ rho = Math.sqrt(-2 * Math.log(1 - Random.new.rand))
6
+ scale = stddev * rho
7
+ return [0, mean + scale * Math.cos(theta)].max
8
+ end
9
+
10
+ def random_title
11
+ if rand < 0.5
12
+ "#{Faker::Hacker.ingverb} #{Faker::Hacker.adjective} #{Faker::Hacker.noun}"
13
+ else
14
+ Faker::Book.title
15
+ end
16
+ end
17
+
18
+ def build!
19
+ Post.destroy_all
20
+ Comment.destroy_all
21
+ Author.destroy_all
22
+
23
+ authors = ([
24
+ "Shay Sides",
25
+ "Teodoro Rainey",
26
+ "Norman Hanley",
27
+ "Raleigh Townes",
28
+ "Samatha Doan",
29
+ "Valeria Seward",
30
+ "Jewel Cervantes",
31
+ "Fallon Clapp",
32
+ "Kenna Marlow",
33
+ "Maurine Butterfield",
34
+ "Teresa Gonzales",
35
+ "Becky Silva",
36
+ "Frank Robertson",
37
+ "Alex Hamilton",
38
+ "Emilio Powell",
39
+ "Jerry Zimmerman",
40
+ ] + 20.times.map { Faker::Name.name }).map do |name|
41
+ Author.create!(name: name)
42
+ end
43
+
44
+ titles = [
45
+ "The 17 Cutest Ways To Eat A Burrito Of The Post-Y2K Era",
46
+ "22 Problems Only Cover Bands Will Understand",
47
+ "The 26 Most Beloved Things Of The '80s",
48
+ "The 18 Greatest Facts Of 2013",
49
+ "39 Real Estate Moguls Who Absolutely Nailed It In 2013",
50
+ "34 Painful Truths Only NFL Linebackers Will Understand",
51
+ "The 43 Most Important Punctuation Marks In South America",
52
+ "The 25 Most Picturesque HBO Shows Of The Last 10 Years",
53
+ "The 45 Best Oprah-Grams From The Ocean Floor",
54
+ "20 Tweets That Look Like Miley Cyrus",
55
+ "The 44 iPhone Apps That Look Like Channing Tatum",
56
+ "The 14 Most Wanted Truths Of All Time",
57
+ "The 37 Most Courageous Horses Of The '90s"
58
+ ] + 1000.times.map { random_title }
59
+
60
+ author_likeability = authors.each_with_object({}) do |author, h|
61
+ average_likes = gaussian(10, 5)
62
+ stddev_likes = gaussian(10, 2.5)
63
+ h[author] = [average_likes, stddev_likes]
64
+ end
65
+
66
+ likeability_for = Hash.new { |author_hash, author|
67
+ author_hash[author] = Hash.new { |title_hash, title|
68
+ average_likes, stddev_likes = author_likeability[author]
69
+ title_hash[title] = [average_likes * (1+rand), stddev_likes]
70
+ }
71
+ }
72
+
73
+ titles.each do |title|
74
+ if rand < 0.5
75
+ author = authors.sample
76
+ else
77
+ author_index = gaussian(authors.length/2, authors.length/4).to_i
78
+ author = authors[author_index % authors.length]
79
+ end
80
+
81
+ created_at = gaussian(100, 40).days.ago
82
+ likes = gaussian(*likeability_for[author][title]).to_i
83
+ status = Post.statuses.values.sample
84
+ published_at = created_at if [:published, :archived].include?(status)
85
+ category = Post.categories.values.push(nil).sample
86
+
87
+ post = Post.create!(
88
+ title: title,
89
+ created_at: created_at,
90
+ likes: likes,
91
+ author: author,
92
+ status: status,
93
+ published_at: published_at,
94
+ category: category,
95
+ )
96
+
97
+ gaussian(8, 4).to_i.times do
98
+ likes = gaussian(5, 2).to_i
99
+ author = authors.sample
100
+ created_at = post.created_at + gaussian(10, 5).days
101
+
102
+ Comment.create!(
103
+ post: post,
104
+ likes: likes,
105
+ author: author,
106
+ created_at: created_at
107
+ )
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end