Created
October 29, 2015 16:12
-
-
Save repeatedly/bc6d692ef6192489d520 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'benchmark' | |
require 'ostruct' | |
# | |
#% ruby bench_filter.rb | |
#Rehearsal ------------------------------------------------------- | |
#placeholder 0.120000 0.000000 0.120000 ( 0.128608) | |
#ruby placeholder 0.550000 0.000000 0.550000 ( 0.548257) | |
#dynamic placeholder 0.190000 0.000000 0.190000 ( 0.196362) | |
#---------------------------------------------- total: 0.860000sec | |
# | |
# user system total real | |
#placeholder 0.120000 0.000000 0.120000 ( 0.123801) | |
#ruby placeholder 0.550000 0.000000 0.550000 ( 0.556790) | |
#dynamic placeholder 0.180000 0.000000 0.180000 ( 0.189357) | |
class PlaceholderExpander | |
attr_reader :placeholders, :log | |
def initialize(params) | |
@log = params[:log] | |
@auto_typecast = params[:auto_typecast] | |
end | |
def prepare_placeholders(time, record, opts) | |
placeholders = { '${time}' => Time.at(time).to_s } | |
record.each {|key, value| placeholders.store("${#{key}}", value) } | |
opts.each do |key, value| | |
if value.kind_of?(Array) # tag_parts, etc | |
size = value.size | |
value.each_with_index { |v, idx| | |
placeholders.store("${#{key}[#{idx}]}", v) | |
placeholders.store("${#{key}[#{idx-size}]}", v) # support [-1] | |
} | |
else # string, interger, float, and others? | |
placeholders.store("${#{key}}", value) | |
end | |
end | |
@placeholders = placeholders | |
end | |
def expand(str, force_stringify=false) | |
if @auto_typecast and !force_stringify | |
single_placeholder_matched = str.match(/\A(\${[^}]+}|__[A-Z_]+__)\z/) | |
if single_placeholder_matched | |
return @placeholders[single_placeholder_matched[1]] | |
end | |
end | |
str.gsub(/(\${[^}]+}|__[A-Z_]+__)/) { | |
@placeholders[$1] | |
} | |
end | |
end | |
class RubyPlaceholderExpander | |
attr_reader :placeholders, :log | |
def initialize(params) | |
@log = params[:log] | |
@auto_typecast = params[:auto_typecast] | |
end | |
# Get placeholders as a struct | |
# | |
# @param [Time] time the time | |
# @param [Hash] record the record | |
# @param [Hash] opts others | |
def prepare_placeholders(time, record, opts) | |
struct = UndefOpenStruct.new(record) | |
struct.time = Time.at(time) | |
opts.each {|key, value| struct.__send__("#{key}=", value) } | |
@placeholders = struct | |
end | |
def expand(_str_for_eval_, force_stringify=false) | |
if @auto_typecast and !force_stringify | |
_single_placeholder_matched_ = _str_for_eval_.match(/\A\${([^}]+)}\z/) | |
if _single_placeholder_matched_ | |
return eval _single_placeholder_matched_[1], @placeholders.instance_eval { binding } | |
end | |
end | |
_interpolated_for_eval_ = _str_for_eval_.gsub(/\$\{([^}]+)\}/, '#{\1}') # ${..} => #{..} | |
eval "\"#{_interpolated_for_eval_}\"", @placeholders.instance_eval { binding } | |
rescue => e | |
log.warn "failed to expand `#{_str_for_eval_}`", :error_class => e.class, :error => e.message | |
log.warn_backtrace | |
nil | |
end | |
class UndefOpenStruct < OpenStruct | |
(Object.instance_methods).each do |m| | |
undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/ | |
end | |
end | |
end | |
class DynamicExpander | |
def initialize(param) | |
(class << self; self; end).module_eval { | |
define_method(:expand) { |tag, time, record| | |
eval(param) | |
} | |
} | |
end | |
end | |
n = 10 | |
tag = 'test_tag' | |
time = Time.now.to_i | |
map = {'field_test' => '${message}', 'tag_test' => '${tag}', 'time_test' => '${time}'} | |
records = [] | |
1000.times { |i| | |
records << {'num' => i, 'message' => 'hello'} | |
} | |
placeholders = {'tag' => tag} | |
pe = PlaceholderExpander.new({}) | |
rpe = RubyPlaceholderExpander.new({}) | |
dexpanders = { | |
'field_test' => DynamicExpander.new("record['message']"), | |
'tag_test' => DynamicExpander.new("tag"), | |
'time_test' => DynamicExpander.new("Time.at(time).to_s") | |
} | |
Benchmark.bmbm do |x| | |
x.report('placeholder') { | |
n.times do | |
records.each { |r| | |
pe.prepare_placeholders(time, r, placeholders) | |
new_record = {} | |
map.each_pair { |k, v| | |
new_record[k] = pe.expand(v) | |
} | |
} | |
#p new_record | |
end } | |
x.report('ruby placeholder') { | |
n.times do | |
records.each { |r| | |
rpe.prepare_placeholders(time, r, placeholders) | |
new_record = {} | |
map.each_pair { |k, v| | |
new_record[k] = rpe.expand(v) | |
} | |
} | |
#p new_record | |
end } | |
x.report('dynamic placeholder') { | |
n.times do | |
records.each { |r| | |
new_record = {} | |
map.each_pair { |k, v| | |
new_record[k] = dexpanders[k].expand(tag, time, r) | |
} | |
} | |
#p new_record | |
end } | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment