octocore-cassandra 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.md +12 -0
  3. data/CONTRIBUTING +0 -0
  4. data/Gemfile +10 -0
  5. data/LICENSE +202 -0
  6. data/MAINTAINERS +0 -0
  7. data/NOTICE +8 -0
  8. data/README.md +69 -0
  9. data/Rakefile +142 -0
  10. data/bin/fakestream-cassandra +258 -0
  11. data/bin/octocore-admin-cassandra +54 -0
  12. data/lib/octocore-cassandra.rb +152 -0
  13. data/lib/octocore-cassandra/baseline.rb +131 -0
  14. data/lib/octocore-cassandra/callbacks.rb +117 -0
  15. data/lib/octocore-cassandra/config.rb +39 -0
  16. data/lib/octocore-cassandra/config/config.yml +1 -0
  17. data/lib/octocore-cassandra/config/search/index/user.yml +42 -0
  18. data/lib/octocore-cassandra/counter.rb +265 -0
  19. data/lib/octocore-cassandra/counter/helpers.rb +168 -0
  20. data/lib/octocore-cassandra/email.rb +63 -0
  21. data/lib/octocore-cassandra/featureflag.rb +79 -0
  22. data/lib/octocore-cassandra/helpers.rb +6 -0
  23. data/lib/octocore-cassandra/helpers/api_consumer_helper.rb +51 -0
  24. data/lib/octocore-cassandra/helpers/api_helper.rb +65 -0
  25. data/lib/octocore-cassandra/helpers/api_logger.rb +14 -0
  26. data/lib/octocore-cassandra/helpers/client_helper.rb +104 -0
  27. data/lib/octocore-cassandra/helpers/kong_helper.rb +164 -0
  28. data/lib/octocore-cassandra/helpers/sinatra_helper.rb +22 -0
  29. data/lib/octocore-cassandra/kafka_bridge.rb +60 -0
  30. data/lib/octocore-cassandra/kldivergence.rb +14 -0
  31. data/lib/octocore-cassandra/mailer.rb +1 -0
  32. data/lib/octocore-cassandra/mailer/subscriber_mailer.rb +30 -0
  33. data/lib/octocore-cassandra/message_parser.rb +114 -0
  34. data/lib/octocore-cassandra/models.rb +274 -0
  35. data/lib/octocore-cassandra/models/contactus.rb +42 -0
  36. data/lib/octocore-cassandra/models/enterprise.rb +76 -0
  37. data/lib/octocore-cassandra/models/enterprise/adapter_details.rb +18 -0
  38. data/lib/octocore-cassandra/models/enterprise/api_event.rb +14 -0
  39. data/lib/octocore-cassandra/models/enterprise/api_hit.rb +20 -0
  40. data/lib/octocore-cassandra/models/enterprise/api_key.rb +11 -0
  41. data/lib/octocore-cassandra/models/enterprise/api_track.rb +13 -0
  42. data/lib/octocore-cassandra/models/enterprise/app_init.rb +13 -0
  43. data/lib/octocore-cassandra/models/enterprise/app_login.rb +12 -0
  44. data/lib/octocore-cassandra/models/enterprise/app_logout.rb +12 -0
  45. data/lib/octocore-cassandra/models/enterprise/authorization.rb +67 -0
  46. data/lib/octocore-cassandra/models/enterprise/category.rb +14 -0
  47. data/lib/octocore-cassandra/models/enterprise/category_baseline.rb +19 -0
  48. data/lib/octocore-cassandra/models/enterprise/category_hit.rb +26 -0
  49. data/lib/octocore-cassandra/models/enterprise/category_trend.rb +19 -0
  50. data/lib/octocore-cassandra/models/enterprise/conversions.rb +69 -0
  51. data/lib/octocore-cassandra/models/enterprise/ctr.rb +54 -0
  52. data/lib/octocore-cassandra/models/enterprise/dimension_choice.rb +21 -0
  53. data/lib/octocore-cassandra/models/enterprise/engagement_time.rb +43 -0
  54. data/lib/octocore-cassandra/models/enterprise/funnel_data.rb +20 -0
  55. data/lib/octocore-cassandra/models/enterprise/funnel_tracker.rb +19 -0
  56. data/lib/octocore-cassandra/models/enterprise/funnels.rb +129 -0
  57. data/lib/octocore-cassandra/models/enterprise/gcm.rb +21 -0
  58. data/lib/octocore-cassandra/models/enterprise/newsfeed_hit.rb +52 -0
  59. data/lib/octocore-cassandra/models/enterprise/notification_hit.rb +42 -0
  60. data/lib/octocore-cassandra/models/enterprise/page.rb +15 -0
  61. data/lib/octocore-cassandra/models/enterprise/page_view.rb +14 -0
  62. data/lib/octocore-cassandra/models/enterprise/pageload_time.rb +43 -0
  63. data/lib/octocore-cassandra/models/enterprise/product.rb +22 -0
  64. data/lib/octocore-cassandra/models/enterprise/product_baseline.rb +20 -0
  65. data/lib/octocore-cassandra/models/enterprise/product_hit.rb +26 -0
  66. data/lib/octocore-cassandra/models/enterprise/product_page_view.rb +13 -0
  67. data/lib/octocore-cassandra/models/enterprise/product_trend.rb +18 -0
  68. data/lib/octocore-cassandra/models/enterprise/push_key.rb +15 -0
  69. data/lib/octocore-cassandra/models/enterprise/rules.rb +45 -0
  70. data/lib/octocore-cassandra/models/enterprise/segment.rb +65 -0
  71. data/lib/octocore-cassandra/models/enterprise/segment_data.rb +22 -0
  72. data/lib/octocore-cassandra/models/enterprise/tag.rb +14 -0
  73. data/lib/octocore-cassandra/models/enterprise/tag_baseline.rb +19 -0
  74. data/lib/octocore-cassandra/models/enterprise/tag_hit.rb +26 -0
  75. data/lib/octocore-cassandra/models/enterprise/tag_trend.rb +19 -0
  76. data/lib/octocore-cassandra/models/enterprise/template.rb +18 -0
  77. data/lib/octocore-cassandra/models/plans.rb +17 -0
  78. data/lib/octocore-cassandra/models/subscribe.rb +13 -0
  79. data/lib/octocore-cassandra/models/user.rb +15 -0
  80. data/lib/octocore-cassandra/models/user/push_token.rb +15 -0
  81. data/lib/octocore-cassandra/models/user/user_browser_details.rb +16 -0
  82. data/lib/octocore-cassandra/models/user/user_location_history.rb +15 -0
  83. data/lib/octocore-cassandra/models/user/user_persona.rb +101 -0
  84. data/lib/octocore-cassandra/models/user/user_phone_details.rb +17 -0
  85. data/lib/octocore-cassandra/models/user/user_profile.rb +20 -0
  86. data/lib/octocore-cassandra/models/user/user_timeline.rb +111 -0
  87. data/lib/octocore-cassandra/record.rb +20 -0
  88. data/lib/octocore-cassandra/schedeuleable.rb +20 -0
  89. data/lib/octocore-cassandra/scheduler.rb +72 -0
  90. data/lib/octocore-cassandra/search.rb +5 -0
  91. data/lib/octocore-cassandra/search/client.rb +33 -0
  92. data/lib/octocore-cassandra/search/indexer.rb +0 -0
  93. data/lib/octocore-cassandra/search/searchable.rb +18 -0
  94. data/lib/octocore-cassandra/search/setup.rb +71 -0
  95. data/lib/octocore-cassandra/segment.rb +287 -0
  96. data/lib/octocore-cassandra/stats.rb +33 -0
  97. data/lib/octocore-cassandra/trendable.rb +88 -0
  98. data/lib/octocore-cassandra/trends.rb +158 -0
  99. data/lib/octocore-cassandra/utils.rb +90 -0
  100. data/lib/octocore-cassandra/version.rb +4 -0
  101. data/spec/lib/stats_spec.rb +20 -0
  102. data/spec/spec_helper.rb +103 -0
  103. metadata +490 -0
@@ -0,0 +1,33 @@
1
+ require 'statsd-ruby'
2
+
3
+ module Octo
4
+
5
+ # Instrumentation and Statistical module
6
+ module Stats
7
+
8
+ # Instrument a block identified by its name
9
+ # @param [Symbol] name The name by which this would be identified
10
+ def instrument(name)
11
+ if stats
12
+ stats.time(name.to_s, &Proc.new)
13
+ else
14
+ yield
15
+ end
16
+ end
17
+
18
+ # Get stats instance
19
+ def stats
20
+ if statd_config
21
+ @statsd = Statsd.new(*statd_config.values) unless @statsd
22
+ @statsd
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ # Get stats config from Octo
29
+ def statd_config
30
+ Octo.get_config :statsd
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,88 @@
1
+ require 'octocore-cassandra/kldivergence'
2
+ require 'octocore-cassandra/counter'
3
+
4
+ module Octo
5
+
6
+ module Trendable
7
+
8
+ include Octo::KLDivergence
9
+
10
+ # Define the columns necessary for a trendable model
11
+ def trendables
12
+ column :divergence, :float
13
+ column :obp, :float
14
+ end
15
+
16
+ # Define the baseline class for this trend
17
+ def baseline(klass)
18
+ @baseline_klass = klass
19
+ end
20
+
21
+ # Define the class for trends
22
+ def trends_class(klass)
23
+ @trends_klass = klass
24
+ end
25
+
26
+ # Aggregates and attempts to store it into the database. This would only
27
+ # work if the class that extends Octo::Counter includes from
28
+ # Cequel::Record
29
+ def aggregate!(ts = Time.now.floor)
30
+ unless self.ancestors.include?Cequel::Record
31
+ raise NoMethodError, 'aggregate! not defined for this counter'
32
+ end
33
+
34
+ aggr = aggregate(ts)
35
+ sum = aggregate_sum(aggr)
36
+ aggr.each do |_ts, counterVals|
37
+ counterVals.each do |obj, count|
38
+ counter = self.new
39
+ counter.enterprise_id = obj.enterprise.id
40
+ counter.uid = obj.unique_id
41
+ counter.count = count
42
+ counter.type = Octo::Counter::TYPE_MINUTE
43
+ counter.ts = _ts
44
+ totalCount = sum[_ts][obj.enterprise_id.to_s].to_f
45
+ counter.obp = (count * 1.0)/totalCount
46
+
47
+ baseline_value = get_baseline_value(:TYPE_MINUTE, obj)
48
+ counter.divergence = kl_divergence(counter.obp,
49
+ baseline_value)
50
+ counter.save!
51
+ end
52
+ end
53
+ call_completion_hook(Octo::Counter::TYPE_MINUTE, ts)
54
+ end
55
+
56
+ private
57
+
58
+ # Aggregates to find the sum of all counters for an enterprise
59
+ # at a time
60
+ # @param [Hash] aggr The aggregated hash
61
+ # @return [Hash] The summed up hash
62
+ def aggregate_sum(aggr)
63
+ sum = {}
64
+ aggr.each do |ts, counterVals|
65
+ sum[ts] = {} unless sum.has_key?ts
66
+ counterVals.each do |obj, count|
67
+ if obj.respond_to?(:enterprise_id)
68
+ eid = obj.public_send(:enterprise_id).to_s
69
+ sum[ts][eid] = sum[ts].fetch(eid, 0) + count
70
+ end
71
+ end
72
+ end
73
+ sum
74
+ end
75
+
76
+ # Get the baseline value for an object.
77
+ # @param [Fixnum] baseline_type The type of baseline to fetch
78
+ # @param [Object] object The object for which baseline is to
79
+ # be fetched
80
+ def get_baseline_value(baseline_type, object)
81
+ clazz = @baseline_klass.constantize
82
+ clazz.public_send(:get_baseline_value, baseline_type, object)
83
+ end
84
+
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,158 @@
1
+ require 'octocore-cassandra/baseline'
2
+ require 'octocore-cassandra/counter'
3
+
4
+ module Octo
5
+
6
+ module Trends
7
+
8
+ include Octo::Counter::Helper
9
+
10
+ DEFAULT_COUNT = 10
11
+
12
+ # Define the columns needed for Trends
13
+ def trendable
14
+ key :type, :int
15
+ key :ts, :timestamp
16
+ key :rank, :int
17
+
18
+ column :score, :float
19
+ column :uid, :text
20
+
21
+ generate_aggregators { |ts, method|
22
+ trendtype = method_names_type_counter(method)
23
+ aggregate_and_create trendtype, ts
24
+ }
25
+
26
+ end
27
+
28
+ # Aggregates and creates trends for all the enterprises for a specific
29
+ # trend type at a specific timestamp
30
+ # @param [Fixnum] oftype The type of trend to be calculated
31
+ # @param [Time] ts The time at which trend needs to be calculated
32
+ def aggregate_and_create(oftype, ts = Time.now.floor)
33
+ Octo::Enterprise.each do |enterprise|
34
+ calculate(enterprise.id, oftype, ts)
35
+ end
36
+ end
37
+
38
+ # Override the aggregate! defined in counter class as the calculations
39
+ # for trending are a little different
40
+ def aggregate!(ts = Time.now.floor)
41
+ aggregate_and_create(Octo::Counter::TYPE_MINUTE, ts)
42
+ end
43
+
44
+ # Performs the actual trend calculation
45
+ # @param [String] enterprise_id The enterprise ID for whom trend needs to be found
46
+ # @param [Fixnum] trend_type The trend type to be calculates
47
+ # @param [Time] ts The Timestamp at which trend needs to be calculated.
48
+ def calculate(enterprise_id, trend_type, ts = Time.now.floor)
49
+ args = {
50
+ enterprise_id: enterprise_id,
51
+ ts: ts,
52
+ type: trend_type
53
+ }
54
+
55
+ klass = @trend_for.constantize
56
+ hitsResult = klass.public_send(:where, args)
57
+ trends = hitsResult.map { |h| counter2trend(h) }
58
+
59
+ # group trends as per the time of their happening and rank them on their
60
+ # score
61
+ grouped_trends = trends.group_by { |x| x.ts }
62
+ grouped_trends.each do |_ts, trendlist|
63
+ sorted_trendlist = trendlist.sort_by { |x| x.score }
64
+ sorted_trendlist.each_with_index do |trend, index|
65
+ trend.rank = index
66
+ trend.type = trend_type
67
+ trend.save!
68
+ end
69
+ end
70
+ end
71
+
72
+ # Define the class for which trends shall be found
73
+ def trend_for(klass)
74
+ unless klass.constantize.ancestors.include?Cequel::Record
75
+ raise ArgumentError, "Class #{ klass } does not represent a DB Model"
76
+ else
77
+ @trend_for = klass
78
+ end
79
+ end
80
+
81
+ # Define the class which would be returned while fetching trending objects
82
+ def trend_class(klass)
83
+ @trend_class = klass
84
+ end
85
+
86
+ # Gets the trend of a type at a time
87
+ # @param [String] enterprise_id The ID of enterprise for whom trend to fetch
88
+ # @param [Fixnum] type The type of trend to fetch
89
+ # @param [Hash] opts The options to be provided for finding trends
90
+ def get_trending(enterprise_id, type, opts={})
91
+ ts = opts.fetch(:ts, Time.now.floor)
92
+ args = {
93
+ enterprise_id: enterprise_id,
94
+ ts: opts.fetch(:ts, Time.now.floor),
95
+ type: type
96
+ }
97
+ res = where(args).limit(opts.fetch(:limit, DEFAULT_COUNT))
98
+ enterprise = Octo::Enterprise.find_by_id(enterprise_id)
99
+ if res.count == 0 and enterprise.fakedata?
100
+ Octo.logger.info 'Beginning to fake data'
101
+ res = []
102
+ if ts.class == Range
103
+ ts_begin = ts.begin
104
+ ts_end = ts.end
105
+ ts_begin.to(ts_end, 1.day).each do |_ts|
106
+ 3.times do |rank|
107
+ items = @trend_class.constantize.send(:where, {enterprise_id: enterprise_id}).first(10)
108
+ if items.count > 0
109
+ uid = items.shuffle.pop.unique_id
110
+ _args = args.merge( ts: _ts, rank: rank, score: rank+1, uid: uid )
111
+ res << self.new(_args).save!
112
+ end
113
+ end
114
+ end
115
+ elsif ts.class == Time
116
+ 3.times do |rank|
117
+ uid = 0
118
+ items = @trend_class.constantize.send(:where, {enterprise_id: enterprise_id}).first(10)
119
+ if items.count > 0
120
+ uid = items.shuffle.pop.unique_id
121
+ _args = args.merge( rank: rank, score: rank+1, uid: uid )
122
+ res << self.new(_args).save!
123
+ end
124
+ end
125
+ end
126
+ end
127
+ res.map do |r|
128
+ clazz = @trend_class.constantize
129
+ clazz.public_send(:recreate_from, r)
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ # Converts a couunter into a trend
136
+ # @param [Object] counter A counter object. This object must belong
137
+ # to one of the counter types defined in models.
138
+ # @return [Object] Returns a trend instance corresponding to the counter
139
+ # instance
140
+ def counter2trend(counter)
141
+ self.new({
142
+ enterprise: counter.enterprise,
143
+ score: score(counter.divergence),
144
+ uid: counter.uid,
145
+ ts: counter.ts
146
+ })
147
+ end
148
+
149
+ # For now, just make sure divergence is absolute. This is responsible to
150
+ # score a counter on the basis of its divergence
151
+ # @param [Float] divergence The divergence value
152
+ # @return [Float] The score
153
+ def score(divergence)
154
+ return 0 if divergence.nil?
155
+ divergence.abs
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,90 @@
1
+ require 'set'
2
+
3
+ module Octo
4
+
5
+ module Utils
6
+
7
+ class << self
8
+
9
+ # Serialize one record before adding it to the cache. Creates a ruby byte
10
+ # stream
11
+ # @param [Object] record Any object to be serialized
12
+ def serialize(record)
13
+ Marshal::dump(record).to_s
14
+ end
15
+
16
+ # Deserialize a data.
17
+ # @param [String] data A string containing Marshal dump of the object
18
+ def deserialize(data)
19
+ Marshal::load(data)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ class ::Time
26
+
27
+ # Find floor time
28
+ # @param [Fixnum] height The minutes of height for floor. Defaults to 1
29
+ def floor(height = 1)
30
+ if height < 1
31
+ height = 1
32
+ end
33
+ sec = height.to_i * 60
34
+ Time.at((self.to_i / sec).round * sec)
35
+ end
36
+
37
+ # Find ceil time
38
+ # @param [Fixnum] height The minutes of height for ceil. Defaults to 1
39
+ def ceil(height = 1)
40
+ if height < 1
41
+ height = 1
42
+ end
43
+ sec = height.to_i * 60
44
+ Time.at((1 + (self.to_i / sec)).round * sec)
45
+ end
46
+
47
+ # Finds the steps between two time.
48
+ # @param [Time] to The end time
49
+ # @param [Time] step The step time. Defaults to 15.minute
50
+ # @return [Array<Time>] An array containint times
51
+ def to(to, step = 15.minutes)
52
+ [self].tap { |array| array << array.last + step while array.last < to }
53
+ end
54
+
55
+ end
56
+
57
+ class ::String
58
+
59
+ # Create a custom method to convert strings to Slugs
60
+ def to_slug
61
+ #strip the string
62
+ ret = self.strip
63
+
64
+ #blow away apostrophes
65
+ ret.gsub!(/['`]/,'')
66
+
67
+ # @ --> at, and & --> and
68
+ ret.gsub!(/\s*@\s*/, ' at ')
69
+ ret.gsub!(/\s*&\s*/, ' and ')
70
+
71
+ #replace all non alphanumeric, underscore or periods with underscore
72
+ ret.gsub!(/\s*[^A-Za-z0-9\.\-]\s*/, '_')
73
+
74
+ #convert double underscores to single
75
+ ret.gsub!(/_+/,'_')
76
+
77
+ #strip off leading/trailing underscore
78
+ ret.gsub!(/\A[_\.]+|[_\.]+\z/,'')
79
+
80
+ ret
81
+ end
82
+
83
+ end
84
+
85
+ class ::Hash
86
+ def deep_merge(second)
87
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
88
+ self.merge(second.to_h, &merger)
89
+ end
90
+ end
@@ -0,0 +1,4 @@
1
+ module Octo
2
+ # The current version of the library
3
+ VERSION = '0.0.6'
4
+ end
@@ -0,0 +1,20 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Octo::Stats do
4
+
5
+ describe '#instrument' do
6
+ let(:dummy_class) { Class.new { extend Octo::Stats } }
7
+
8
+ it 'yields the given block' do
9
+ block = Proc.new { puts 'hello world' }
10
+ name = :hello_world
11
+
12
+ expect(dummy_class).to receive(:instrument).
13
+ with(name, &block).
14
+ and_yield(&block)
15
+
16
+ dummy_class.instrument(name, &block)
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,103 @@
1
+ require 'bundler/setup'
2
+ require 'rspec'
3
+
4
+ Bundler.setup
5
+
6
+ require 'octocore'
7
+
8
+ # This file was generated by the `rspec --init` command. Conventionally, all
9
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
10
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
11
+ # this file to always be loaded, without a need to explicitly require it in any
12
+ # files.
13
+ #
14
+ # Given that it is always loaded, you are encouraged to keep this file as
15
+ # light-weight as possible. Requiring heavyweight dependencies from this file
16
+ # will add to the boot time of your test suite on EVERY test run, even for an
17
+ # individual file that may not need all of that loaded. Instead, consider making
18
+ # a separate helper file that requires the additional dependencies and performs
19
+ # the additional setup, and require it from the spec files that actually need
20
+ # it.
21
+ #
22
+ # The `.rspec` file also contains a few flags that are not defaults but that
23
+ # users commonly want.
24
+ #
25
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
26
+ RSpec.configure do |config|
27
+ # rspec-expectations config goes here. You can use an alternate
28
+ # assertion/expectation library such as wrong or the stdlib/minitest
29
+ # assertions if you prefer.
30
+ config.expect_with :rspec do |expectations|
31
+ # This option will default to `true` in RSpec 4. It makes the `description`
32
+ # and `failure_message` of custom matchers include text for helper methods
33
+ # defined using `chain`, e.g.:
34
+ # be_bigger_than(2).and_smaller_than(4).description
35
+ # # => "be bigger than 2 and smaller than 4"
36
+ # ...rather than:
37
+ # # => "be bigger than 2"
38
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
39
+ end
40
+
41
+ # rspec-mocks config goes here. You can use an alternate test double
42
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
43
+ config.mock_with :rspec do |mocks|
44
+ # Prevents you from mocking or stubbing a method that does not exist on
45
+ # a real object. This is generally recommended, and will default to
46
+ # `true` in RSpec 4.
47
+ mocks.verify_partial_doubles = true
48
+ end
49
+
50
+ # The settings below are suggested to provide a good initial experience
51
+ # with RSpec, but feel free to customize to your heart's content.
52
+ =begin
53
+ # These two settings work together to allow you to limit a spec run
54
+ # to individual examples or groups you care about by tagging them with
55
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
56
+ # get run.
57
+ config.filter_run :focus
58
+ config.run_all_when_everything_filtered = true
59
+
60
+ # Allows RSpec to persist some state between runs in order to support
61
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
62
+ # you configure your source control system to ignore this file.
63
+ config.example_status_persistence_file_path = "spec/examples.txt"
64
+
65
+ # Limits the available syntax to the non-monkey patched syntax that is
66
+ # recommended. For more details, see:
67
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
68
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
69
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
70
+ config.disable_monkey_patching!
71
+
72
+ # This setting enables warnings. It's recommended, but in some cases may
73
+ # be too noisy due to issues in dependencies.
74
+ config.warnings = true
75
+
76
+ # Many RSpec users commonly either run the entire suite or an individual
77
+ # file, and it's useful to allow more verbose output when running an
78
+ # individual spec file.
79
+ if config.files_to_run.one?
80
+ # Use the documentation formatter for detailed output,
81
+ # unless a formatter has already been configured
82
+ # (e.g. via a command-line flag).
83
+ config.default_formatter = 'doc'
84
+ end
85
+
86
+ # Print the 10 slowest examples and example groups at the
87
+ # end of the spec run, to help surface which specs are running
88
+ # particularly slow.
89
+ config.profile_examples = 10
90
+
91
+ # Run specs in random order to surface order dependencies. If you find an
92
+ # order dependency and want to debug it, you can fix the order by providing
93
+ # the seed, which is printed after each run.
94
+ # --seed 1234
95
+ config.order = :random
96
+
97
+ # Seed global randomization in this process using the `--seed` CLI option.
98
+ # Setting this allows you to use `--seed` to deterministically reproduce
99
+ # test failures related to randomization by passing the same `--seed` value
100
+ # as the one that triggered the failure.
101
+ Kernel.srand config.seed
102
+ =end
103
+ end