betterplace-bi 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.semaphore/semaphore.yml +26 -0
- data/.tool-versions +2 -0
- data/.utilsrc +26 -0
- data/Gemfile +5 -0
- data/README.md +76 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/betterplace-bi.gemspec +39 -0
- data/lib/betterplace-bi.rb +1 -0
- data/lib/bi/ab_test_helper.rb +81 -0
- data/lib/bi/api.rb +115 -0
- data/lib/bi/commands/base.rb +11 -0
- data/lib/bi/commands/collector.rb +32 -0
- data/lib/bi/commands/connection.rb +25 -0
- data/lib/bi/commands/delete.rb +33 -0
- data/lib/bi/commands/serializer.rb +40 -0
- data/lib/bi/commands/update.rb +29 -0
- data/lib/bi/commands.rb +10 -0
- data/lib/bi/commands_job.rb +24 -0
- data/lib/bi/event.rb +52 -0
- data/lib/bi/planning_value_parser.rb +100 -0
- data/lib/bi/planning_value_validations.rb +15 -0
- data/lib/bi/railtie.rb +13 -0
- data/lib/bi/request_analyzer.rb +64 -0
- data/lib/bi/session_id.rb +11 -0
- data/lib/bi/shared_value.rb +102 -0
- data/lib/bi/tracking.rb +28 -0
- data/lib/bi/type_generator.rb +79 -0
- data/lib/bi/update_error.rb +4 -0
- data/lib/bi/updater.rb +61 -0
- data/lib/bi/version.rb +8 -0
- data/lib/bi.rb +27 -0
- data/lib/tasks/bime.rake +55 -0
- data/spec/bi/ab_test_helper_spec.rb +145 -0
- data/spec/bi/commands/collector_spec.rb +26 -0
- data/spec/bi/commands/connection_spec.rb +15 -0
- data/spec/bi/commands_job_spec.rb +24 -0
- data/spec/bi/commands_spec.rb +46 -0
- data/spec/bi/event_spec.rb +77 -0
- data/spec/bi/planning_value_parser_spec.rb +94 -0
- data/spec/bi/request_analyzer_spec.rb +75 -0
- data/spec/bi/shared_value_spec.rb +47 -0
- data/spec/bi/tracking_spec.rb +37 -0
- data/spec/bi/type_generator_spec.rb +44 -0
- data/spec/bi/updater_spec.rb +61 -0
- data/spec/bime_dir/.keep +0 -0
- data/spec/config/bi.yml +18 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/models.rb +106 -0
- metadata +331 -0
data/lib/bi/event.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module BI
|
2
|
+
class Event
|
3
|
+
def self.write(**args)
|
4
|
+
new.write(**args)
|
5
|
+
end
|
6
|
+
|
7
|
+
def event_class
|
8
|
+
cc.bi.event_class.constantize
|
9
|
+
end
|
10
|
+
|
11
|
+
# The parameter +channel+ is the channel that selects an ab test from the
|
12
|
+
# configuration.
|
13
|
+
# The paramter +name+ is the name of the event, e. g. show_form.
|
14
|
+
# The parameter session is either a session object or a session id string.
|
15
|
+
# In the former case the session object will be loaded if hasn't been
|
16
|
+
# loaded yet to generate the unique session id we need..
|
17
|
+
# The remaining parameters +**data+ are passed through to the created event
|
18
|
+
# as tracking parameters.
|
19
|
+
def write(
|
20
|
+
channel:, name:, version:, session:,
|
21
|
+
**data
|
22
|
+
)
|
23
|
+
event_class < BI::Tracking or
|
24
|
+
raise TypeError, 'event class has to mixin BI::Tracking'
|
25
|
+
|
26
|
+
if session.respond_to?(:loaded?)
|
27
|
+
session.loaded? or session.send(:load!)
|
28
|
+
session = BI::SessionID.session_id(session)
|
29
|
+
elsif session.respond_to?(:to_str)
|
30
|
+
session = session.to_str
|
31
|
+
else
|
32
|
+
session = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
created_event = event_class.create!(
|
36
|
+
tracking: {
|
37
|
+
channel: channel,
|
38
|
+
name: name,
|
39
|
+
version: version,
|
40
|
+
session: session,
|
41
|
+
**data.transform_keys { |k| k.to_s.sub(/\Atracking_/, '').to_sym },
|
42
|
+
}
|
43
|
+
)
|
44
|
+
Log.info "Stored a #{self.class} for #{name}",
|
45
|
+
meta: { module: 'bi', event: created_event.attributes }
|
46
|
+
created_event
|
47
|
+
rescue => e
|
48
|
+
Log.error(e, notify: true, meta: { module: 'bi' })
|
49
|
+
raise e
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module BI
|
5
|
+
class PlanningValueParser
|
6
|
+
class ParserError < StandardError
|
7
|
+
attr_accessor :row
|
8
|
+
|
9
|
+
attr_accessor :line
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.parse(csv_text, class_name:)
|
13
|
+
begin
|
14
|
+
model_class = Object.const_get(class_name)
|
15
|
+
rescue NameError
|
16
|
+
raise ParserError, "unknown class name #{class_name.inspect}"
|
17
|
+
end
|
18
|
+
csv_text = csv_text.gsub(/\r\n?/, "\n")
|
19
|
+
errors = {}
|
20
|
+
values = []
|
21
|
+
table = CSV.parse(csv_text, headers: true, row_sep: ?\n, col_sep: ?;)
|
22
|
+
table.each_with_index do |row, i|
|
23
|
+
values << Check.new(row, line: i + 2, class_name: class_name).value
|
24
|
+
rescue ParserError => e
|
25
|
+
errors[e.line] = e.message
|
26
|
+
end
|
27
|
+
new(values, errors: errors, model_class: model_class)
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(values, model_class:, errors: [])
|
31
|
+
@model_class = model_class
|
32
|
+
@values = values
|
33
|
+
@errors = errors
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :model_class
|
37
|
+
|
38
|
+
def import
|
39
|
+
model_class.where(data_version: data_versions).
|
40
|
+
destroy_all
|
41
|
+
each { |pv| pv.save! }
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
include Enumerable
|
46
|
+
def each(&block)
|
47
|
+
@values.each(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def data_versions
|
51
|
+
@values.each_with_object(Set[]) { |v, s| s << v.data_version }.to_a
|
52
|
+
end
|
53
|
+
|
54
|
+
def valid?
|
55
|
+
@errors.blank? && all?(&:valid?)
|
56
|
+
end
|
57
|
+
|
58
|
+
def errors
|
59
|
+
if @errors.present?
|
60
|
+
@errors
|
61
|
+
else
|
62
|
+
@values.each_with_index.each_with_object({}) do |(v, i), errors|
|
63
|
+
v.valid?
|
64
|
+
e = v.errors.messages.full? or next
|
65
|
+
errors[i + 2] = e.transform_values { |value| value.join(' & ') }.
|
66
|
+
map { |a| "%s: %s" % a }.join(' | ')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
VALID_HEADERS = [
|
72
|
+
"amount_in_cents",
|
73
|
+
"data_type",
|
74
|
+
"data_version",
|
75
|
+
"product_tracking",
|
76
|
+
"yearmonth",
|
77
|
+
].sort
|
78
|
+
|
79
|
+
class Check
|
80
|
+
def initialize(row, line:, class_name:)
|
81
|
+
parser_error = ParserError.new.tap { |pe|
|
82
|
+
pe.row = row
|
83
|
+
pe.line = line
|
84
|
+
}
|
85
|
+
if row.size != VALID_HEADERS.size
|
86
|
+
raise parser_error,
|
87
|
+
"#values has to match #headers = #{VALID_HEADERS.size}"
|
88
|
+
end
|
89
|
+
if row.headers.sort != VALID_HEADERS
|
90
|
+
raise parser_error, "headers need to be #{VALID_HEADERS.inspect}"
|
91
|
+
end
|
92
|
+
@value = Object.const_get(class_name).new(row.to_h)
|
93
|
+
end
|
94
|
+
|
95
|
+
attr_reader :value
|
96
|
+
|
97
|
+
delegate :valid?, to: :@value
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module BI
|
2
|
+
module PlanningValueValidations
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
validates :product_tracking, presence: true
|
7
|
+
validates :amount_in_cents, presence: true,
|
8
|
+
numericality: { only_integer: true }
|
9
|
+
validates :yearmonth, presence: true,
|
10
|
+
format: { with: /\A[0-9]{4}-(1[0-2]|0[1-9])\z/ }
|
11
|
+
validates :data_type, presence: true
|
12
|
+
validates :data_version, presence: true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/bi/railtie.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module BI
|
2
|
+
if defined?(Rails::Railtie)
|
3
|
+
class Railtie < Rails::Railtie
|
4
|
+
initializer 'bi.configure_rails_initialization' do |app|
|
5
|
+
app.config.active_job.custom_serializers << BI::Commands::Serializer
|
6
|
+
end
|
7
|
+
|
8
|
+
rake_tasks do
|
9
|
+
load 'tasks/bime.rake'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module BI
|
2
|
+
class RequestAnalyzer
|
3
|
+
def initialize(request)
|
4
|
+
@request = request
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :request
|
8
|
+
|
9
|
+
def user_agent
|
10
|
+
request.user_agent
|
11
|
+
end
|
12
|
+
|
13
|
+
def ignore?
|
14
|
+
preview? || robot?
|
15
|
+
end
|
16
|
+
|
17
|
+
def preview?
|
18
|
+
request.headers['x-purpose'] == 'preview'
|
19
|
+
end
|
20
|
+
|
21
|
+
def robot?
|
22
|
+
robot_regexp.match?(user_agent)
|
23
|
+
end
|
24
|
+
|
25
|
+
def mobile?
|
26
|
+
mobile_regexp.match?(user_agent)
|
27
|
+
end
|
28
|
+
|
29
|
+
def device_type
|
30
|
+
case
|
31
|
+
when mobile?
|
32
|
+
:mobile
|
33
|
+
when robot?
|
34
|
+
:bot
|
35
|
+
else
|
36
|
+
:desktop
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def user_agent_configuration
|
43
|
+
cc.bi.requests.user_agents?
|
44
|
+
end
|
45
|
+
|
46
|
+
memoize function:
|
47
|
+
def robot_regexp
|
48
|
+
combine_patterns(user_agent_configuration&.robot?)
|
49
|
+
end
|
50
|
+
|
51
|
+
memoize function:
|
52
|
+
def mobile_regexp
|
53
|
+
combine_patterns(user_agent_configuration&.mobile?)
|
54
|
+
end
|
55
|
+
|
56
|
+
def combine_patterns(patterns)
|
57
|
+
if patterns
|
58
|
+
/\b(?:#{patterns.to_h.keys * ?|})\b|\A\W*\z/i
|
59
|
+
else
|
60
|
+
/\p{^any}/
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'active_support/time'
|
2
|
+
|
3
|
+
module BI
|
4
|
+
module SharedValue
|
5
|
+
extend Tins::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
annotate :field
|
9
|
+
|
10
|
+
include GlobalID::Identification
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def find(id)
|
15
|
+
new(update_class.find(id.ask_and_send_or_self(:id)))
|
16
|
+
end
|
17
|
+
|
18
|
+
implement def update_class() end, :subclass
|
19
|
+
|
20
|
+
GormTimestamp = Struct.new(:type, :gorm)
|
21
|
+
|
22
|
+
memoize function:
|
23
|
+
def bp_timestamp
|
24
|
+
Hash.new do |_, k|
|
25
|
+
raise KeyError, "illegal Attribute name #{k.inspect}"
|
26
|
+
end.merge(
|
27
|
+
Local: GormTimestamp.new('*time.Time', 'gorm:"type:timestamp;index"'),
|
28
|
+
YearLocal: GormTimestamp.new('*int', 'gorm:"type:int;index"'),
|
29
|
+
MonthLocal: GormTimestamp.new('*int', 'gorm:"type:int;index"'),
|
30
|
+
DayLocal: GormTimestamp.new('*int', 'gorm:"type:int;index"'),
|
31
|
+
HourLocal: GormTimestamp.new('*int', 'gorm:"type:int;index"'),
|
32
|
+
CWLocal: GormTimestamp.new('*int', 'gorm:"type:int;index"'),
|
33
|
+
DateLocal: GormTimestamp.new('*string', 'gorm:"type:varchar;index"'),
|
34
|
+
YearMonthLocal: GormTimestamp.new('*string', 'gorm:"type:varchar;index"'),
|
35
|
+
YearCWLocal: GormTimestamp.new('*string', 'gorm:"type:varchar;index"'),
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def url(method: 'POST', id: nil)
|
40
|
+
if ep = cc.bi.endpoints[name]
|
41
|
+
if u = ep[method]
|
42
|
+
id and return u = u.sub(':id', id)
|
43
|
+
u
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def clear
|
49
|
+
command = BI::Commands::Delete.new(
|
50
|
+
url: cc.bi.clear.sub(':id', update_class.name)
|
51
|
+
)
|
52
|
+
BI::Commands::Connection.connect_to_server do |connection|
|
53
|
+
command.perform_via(connection)
|
54
|
+
end
|
55
|
+
self
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize(object)
|
60
|
+
if object_uuid = object.ask_and_send(:to_str)
|
61
|
+
object = update_class.find(object_uuid)
|
62
|
+
end
|
63
|
+
@object = object
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def iso_timestamp(time)
|
69
|
+
if time
|
70
|
+
time.in_time_zone('Europe/Berlin').strftime('%FT%T.%6NZ') # with precision 6 sub seconds
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
public
|
75
|
+
|
76
|
+
def update_class
|
77
|
+
self.class.update_class
|
78
|
+
end
|
79
|
+
|
80
|
+
def url(**args)
|
81
|
+
self.class.url(**args)
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
"#<#{self.class} type=#{update_class} id=#{@object.id}>"
|
86
|
+
end
|
87
|
+
|
88
|
+
def attributes
|
89
|
+
field_annotations.each_with_object({}) do |(name, opts), result|
|
90
|
+
result[name] = __send__(name)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def as_json(*)
|
95
|
+
attributes
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_json(*a)
|
99
|
+
as_json.to_json(*a)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/bi/tracking.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module BI
|
2
|
+
module Tracking
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
serialize :tracking, coder: JSON
|
7
|
+
end
|
8
|
+
|
9
|
+
def tracking_hash
|
10
|
+
tracking.to_h.symbolize_keys
|
11
|
+
end
|
12
|
+
|
13
|
+
def respond_to_missing?(name, include_private = false)
|
14
|
+
name =~ /\Atracking_(.+=|.*[^?!])\z/ or super
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(name, *args, &block)
|
18
|
+
case name
|
19
|
+
when /\Atracking_(.+)=\z/
|
20
|
+
tracking[$1] = args.first
|
21
|
+
when /\Atracking_(.*[^?!])\z/
|
22
|
+
tracking[$1]
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module BI
|
2
|
+
class TypeGenerator
|
3
|
+
def initialize(output_dir: cc.bi.bime_dir)
|
4
|
+
@output_dir = Pathname.new(output_dir)
|
5
|
+
@value_classes = cc.bi.endpoints.attribute_names.
|
6
|
+
map(&:to_s).map(&:constantize)
|
7
|
+
end
|
8
|
+
|
9
|
+
def timestamp_value(attribute_name, attribute_suffix, db_value)
|
10
|
+
%{ #{attribute_name + attribute_suffix.to_s} #{db_value.type} `json:"-" #{db_value.gorm}`}
|
11
|
+
end
|
12
|
+
|
13
|
+
def gofmt
|
14
|
+
command = `which gofmt`.chomp
|
15
|
+
return if command.empty?
|
16
|
+
command
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate
|
20
|
+
STDOUT.puts "Generating GO types in directory #{@output_dir}"
|
21
|
+
@value_classes.each do |vc|
|
22
|
+
c = vc.name.demodulize
|
23
|
+
output_filename = @output_dir.join(vc.update_class.name.underscore + ".go")
|
24
|
+
temp_io(name: 'go-type', content: -> src {
|
25
|
+
code = ''
|
26
|
+
STDOUT.print "Generating type code for #{c} …"
|
27
|
+
imports = Set[]
|
28
|
+
vc.field_annotations.each do |name, opts|
|
29
|
+
attribute_name = name.to_s.camelize
|
30
|
+
db = opts.fetch(:db)
|
31
|
+
case type = opts.fetch(:type)
|
32
|
+
when '*time.Time'
|
33
|
+
imports << 'time'
|
34
|
+
code << %{ #{attribute_name} #{type} `json:"#{name}" gorm:"-" timestamp:"split"`\n}
|
35
|
+
db.each do |attribute_suffix, db_value|
|
36
|
+
code << timestamp_value(attribute_name, attribute_suffix, db_value) << "\n"
|
37
|
+
end
|
38
|
+
next
|
39
|
+
when 'pq.StringArray'
|
40
|
+
imports << 'github.com/lib/pq'
|
41
|
+
end
|
42
|
+
code << %{ #{attribute_name} #{type} `json:"#{name}" #{db}`\n}
|
43
|
+
rescue KeyError, NoMethodError => e
|
44
|
+
raise "Error for #{name} #{e.class}: #{e}"
|
45
|
+
end
|
46
|
+
code << "}\n"
|
47
|
+
code = preamble(vc.update_class, imports: imports) + code
|
48
|
+
src.write code
|
49
|
+
STDOUT.puts "done."
|
50
|
+
}) do |src|
|
51
|
+
STDOUT.print "Outputting type code to #{output_filename} …"
|
52
|
+
File.open(output_filename, ?w) do |out|
|
53
|
+
if g = gofmt
|
54
|
+
out.puts `#{g} #{src.path}`
|
55
|
+
else
|
56
|
+
out.puts IO.read(src.path)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
STDOUT.puts "done."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def preamble(type_name, imports:)
|
67
|
+
result = "package bime\n\n"
|
68
|
+
if i = imports.full?(:to_a)
|
69
|
+
result << <<~end
|
70
|
+
import (
|
71
|
+
#{i.map { |x| " #{x.dump}" }.join(?\n)}
|
72
|
+
)
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
result << "type #{type_name} struct {\n"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/bi/updater.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module BI
|
2
|
+
module Updater
|
3
|
+
extend Tins::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_save :schedule_bi_update_job_on_change, if: :changed?
|
7
|
+
|
8
|
+
before_destroy :schedule_bi_update_job_on_change
|
9
|
+
|
10
|
+
after_commit :schedule_bi_update_job
|
11
|
+
|
12
|
+
thread_local :change_detected, false
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
thread_local :bi_commands
|
17
|
+
end
|
18
|
+
|
19
|
+
def schedule_bi_update_job_on_change
|
20
|
+
self.change_detected = true
|
21
|
+
end
|
22
|
+
|
23
|
+
def bi_commands
|
24
|
+
BI::Updater.bi_commands ||= BI::Commands::Collector.new
|
25
|
+
yield BI::Updater.bi_commands
|
26
|
+
if BI::Updater.bi_commands.schedule_job?(self)
|
27
|
+
BI::Updater.bi_commands.schedule_job
|
28
|
+
BI::Updater.bi_commands = nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def bi_update(really = true)
|
33
|
+
if cc.bi.update
|
34
|
+
if really
|
35
|
+
self.change_detected = false # Set to false as early as possible
|
36
|
+
bi_commands do |commands|
|
37
|
+
value_type = "BI::%sValue" % self.class.name
|
38
|
+
begin
|
39
|
+
value_class = value_type.constantize
|
40
|
+
rescue NameError => e
|
41
|
+
BI.error(e, notify: true, meta: { module: 'bi' })
|
42
|
+
else
|
43
|
+
BI::Updater.bi_commands.add(self, value_class)
|
44
|
+
end
|
45
|
+
ask_and_send(:trigger_dependent_updates)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
else
|
49
|
+
Log.info "Would send a BI Command for #{self.class}##{id} if not disabled"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def schedule_bi_update_job(default_change_detected = false)
|
54
|
+
self.change_detected ||= default_change_detected
|
55
|
+
bi_update(change_detected)
|
56
|
+
true
|
57
|
+
ensure
|
58
|
+
self.change_detected = false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/bi/version.rb
ADDED
data/lib/bi.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'complex_config/rude'
|
2
|
+
require 'tins/xt'
|
3
|
+
require 'globalid'
|
4
|
+
require 'excon'
|
5
|
+
require 'logger'
|
6
|
+
require 'betterlog'
|
7
|
+
|
8
|
+
module BI
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'bi/version'
|
12
|
+
require 'bi/railtie'
|
13
|
+
require 'bi/shared_value'
|
14
|
+
require 'bi/type_generator'
|
15
|
+
require 'bi/update_error'
|
16
|
+
require 'bi/updater'
|
17
|
+
require 'bi/commands'
|
18
|
+
require 'bi/commands_job' if defined?(ActiveJob::Base)
|
19
|
+
|
20
|
+
require 'bi/planning_value_validations'
|
21
|
+
require 'bi/planning_value_parser'
|
22
|
+
require 'bi/session_id'
|
23
|
+
require 'bi/event'
|
24
|
+
require 'bi/request_analyzer'
|
25
|
+
require 'bi/tracking'
|
26
|
+
require 'bi/ab_test_helper'
|
27
|
+
require 'bi/api'
|
data/lib/tasks/bime.rake
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
namespace :bime do
|
2
|
+
desc 'Generate golang type definitions'
|
3
|
+
task :types => :environment do
|
4
|
+
BI::TypeGenerator.new.generate
|
5
|
+
end
|
6
|
+
|
7
|
+
silence = proc { |&b| ActiveJob::Base.logger.silence(&b) }
|
8
|
+
|
9
|
+
desc 'Update all BI values'
|
10
|
+
task :update => :environment do |task, args|
|
11
|
+
cc.bi.update or raise "BI Update was disabled in cc.bi.update!"
|
12
|
+
|
13
|
+
args = args.to_a
|
14
|
+
|
15
|
+
if args.empty?
|
16
|
+
args.concat(cc.bi.endpoints.attribute_names.map { |n|
|
17
|
+
n.to_s.demodulize.sub(/Value\z/, '').underscore
|
18
|
+
})
|
19
|
+
end
|
20
|
+
|
21
|
+
models = args.map { |a| a.camelize.constantize }
|
22
|
+
|
23
|
+
silence.() {
|
24
|
+
models.each do |model|
|
25
|
+
model.find_each.with_infobar(label: model.name) do |o|
|
26
|
+
infobar << o.bi_update
|
27
|
+
end
|
28
|
+
infobar.finish
|
29
|
+
infobar.newline
|
30
|
+
end
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'Clear all BI values'
|
35
|
+
task :clear => :environment do |task, args|
|
36
|
+
cc.bi.update or raise "BI Update was disabled in cc.bi.update!"
|
37
|
+
|
38
|
+
args = args.to_a
|
39
|
+
if args.empty?
|
40
|
+
args.concat(cc.bi.endpoints.attribute_names.map { |n|
|
41
|
+
n.to_s.demodulize.sub(/Value\z/, '').underscore
|
42
|
+
})
|
43
|
+
end
|
44
|
+
|
45
|
+
args.each.with_infobar(label: 'BI Values') do |v|
|
46
|
+
infobar << "BI::#{(v + '_value').camelize}".constantize.clear
|
47
|
+
end
|
48
|
+
|
49
|
+
infobar.finish
|
50
|
+
infobar.newline
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'Reset all BI values'
|
54
|
+
task :reset => %i[ clear update ]
|
55
|
+
end
|