liquid-ext 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ccafb95dc4aafbdfcc5c4c75916926fa9a332dcd
4
+ data.tar.gz: 6e9e8d993ae413ca7d0630ea68dc469061195c54
5
+ SHA512:
6
+ metadata.gz: 509061281f8ba50abbcf3463d0c946fbe3fdf1286a6520617fb074f6e9aea4eb1539c88973d1ae59f10f3d22859f34608d79e206d918c28cec43f69715ade016
7
+ data.tar.gz: 697911fda7ae6c9a56c1f50a56e535fbda9bea71702af6b3d036b3d338544b79e8f773c5e18a4e891d5320d446bce476e2321af7151b8117ca4498411ff2538a
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - jruby
4
+ - 2.0.0
5
+ - 1.9.3
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --protected --no-private
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem "liquid-development"
7
+ end
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2012 madvertise Mobile Advertising GmbH
2
+ Copyright (c) 2013 LiquidM, Inc.
3
+
4
+ MIT License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # Liquid Extensions
2
+
3
+ The liquid-ext gem provides a bunch of ruby extensions and common startup/runtime code.
4
+
5
+ [![Build Status](https://secure.travis-ci.org/liquidm/ext.png)](http://travis-ci.org/liquidm/ext)
6
+ [![Code Climate](https://codeclimate.com/github/liquidm/ext.png)](https://codeclimate.com/github/liquidm/ext)
7
+ [![Dependency Status](https://gemnasium.com/liquidm/ext.png)](https://gemnasium.com/liquidm/ext)
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'liquid-ext'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install liquid-ext
22
+
23
+ ## Usage
24
+
25
+ Please refer to the [API documentation](http://rubydoc.info/gems/liquid-ext/frames).
26
+
27
+ ## Contributing
28
+
29
+ 1. Fork it
30
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
31
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
32
+ 4. Push to the branch (`git push origin my-new-feature`)
33
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/setup"
2
+ require "bundler/gem_tasks"
3
+ require "liquid/tasks"
@@ -0,0 +1,9 @@
1
+ java_import 'java.lang.System'
2
+
3
+ module Benchmark
4
+ def realtime(&block)
5
+ t0 = System.nano_time
6
+ yield
7
+ ((System.nano_time - t0).to_f / 1_000_000_000).round(3)
8
+ end
9
+ end
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+
3
+ $:.unshift(ROOT) if defined?(ROOT)
4
+
5
+ # load default configuration
6
+ require 'liquid-logging'
7
+ require 'liquid/configuration'
8
+
9
+ $conf = Configuration.new
10
+
11
+ # configuration-reloading callbacks
12
+ reload_logger = ->(conf) do
13
+ ImprovedLogger::Formatter.format = conf.log_format
14
+ ImprovedLogger::Formatter.log4j_format = conf.log4j_format
15
+
16
+ $log = MultiLogger.new
17
+ $log.attach(ImprovedLogger.new(conf.log_backend.to_sym, File.basename($0)))
18
+ $log.level = conf.log_level.downcase.to_sym
19
+ $log.log_caller = conf.log_caller
20
+
21
+ # sneak this in automatically
22
+ ZK.logger = $log if ::Module.const_defined?(:ZK)
23
+ end
24
+
25
+ reload_mixins = ->(conf) do
26
+ if defined?(ROOT)
27
+ config_yml = File.join(ROOT, 'config.yml')
28
+ conf.mixin(config_yml) if File.exist?(config_yml)
29
+
30
+ dot_user = File.join(ROOT, '.user')
31
+
32
+ if File.exists?(dot_user)
33
+ File.readlines(dot_user).each do |line|
34
+ user_yml = File.join(ROOT, 'config', 'mixins', "#{line.chomp}.yml")
35
+ conf.mixin(user_yml)
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ # reload configuration, trigger callbacks
42
+ $conf.callback(&reload_mixins)
43
+ $conf.callback(&reload_logger)
44
+
45
+ $conf.reload!
46
+
47
+ # load java dependencies
48
+ if RUBY_PLATFORM == 'java'
49
+ begin
50
+ require 'jbundler'
51
+ rescue LoadError
52
+ # do nothing
53
+ end
54
+
55
+ # some java libraries cannot be found on maven central, so we load all bundled
56
+ # jar files here for convenience
57
+ if defined?(ROOT)
58
+ Dir[File.join(ROOT, 'jars', '*.jar')].each do |f|
59
+ require f
60
+ end
61
+ end
62
+ end
63
+
64
+ # load a bunch of common classes here, so we don't have to track and repeat it
65
+ # everywhere
66
+ require 'active_support/all'
67
+ require 'cgi'
68
+ require 'date'
69
+ require 'json'
70
+ require 'socket'
71
+ require 'time'
72
+
73
+ # load all extensions
74
+ Dir[File.join(File.dirname(__FILE__), 'ext', '*.rb')].each do |f|
75
+ require f
76
+ end
77
+
78
+ if RUBY_PLATFORM == 'java'
79
+ require 'liquid/benchmark'
80
+ end
81
+
82
+ require 'liquid/cli'
83
+ require 'liquid/environment'
84
+ require 'liquid/from_file'
85
+ require 'liquid/hash_helper'
86
+ require 'liquid/transaction_id'
data/lib/liquid/cli.rb ADDED
@@ -0,0 +1,80 @@
1
+ # encoding: utf-8
2
+
3
+ require 'liquid/boot'
4
+ require 'mixlib/cli'
5
+
6
+ class CLI
7
+ include Mixlib::CLI
8
+
9
+ option :configfile,
10
+ short: '-c FILE',
11
+ long: '--config FILE',
12
+ description: 'Configuration File to load'
13
+
14
+ option :name,
15
+ :short => '-n NAME',
16
+ :long => '--name NAME',
17
+ :description => 'Process name',
18
+ :default => File.basename($0),
19
+ :proc => ->(value) { $0 = value }
20
+
21
+ option :environment,
22
+ :short => '-e ENVIRONMENT',
23
+ :long => '--environment ENVIRONMENT',
24
+ :description => "Set the daemon environment",
25
+ :default => "development",
26
+ :proc => ->(value) { Env.set(value) }
27
+
28
+ option :debug,
29
+ :short => '-D',
30
+ :long => '--debug',
31
+ :description => "Enable debug output",
32
+ :boolean => true,
33
+ :default => false,
34
+ :proc => ->(value) { $conf.mixin(log_level: value ? :debug : :info); value }
35
+
36
+ option :help,
37
+ :short => '-h',
38
+ :long => '--help',
39
+ :description => "Show this message",
40
+ :on => :tail,
41
+ :boolean => true,
42
+ :show_options => true,
43
+ :exit => 0
44
+
45
+ def option(name, args)
46
+ args[:on] ||= :on
47
+ args[:boolean] ||= false
48
+ args[:required] ||= false
49
+ args[:proc] ||= nil
50
+ args[:show_options] ||= false
51
+ args[:exit] ||= nil
52
+
53
+ if args.has_key?(:default)
54
+ config[name.to_sym] = args[:default]
55
+ end
56
+
57
+ options[name.to_sym] = args
58
+ end
59
+
60
+ def self.for(cls, &block)
61
+ cli = new
62
+ cli.instance_eval(&block) if block_given?
63
+ cli.parse_options
64
+
65
+ $log.info("cli:initialize", cli.config)
66
+ $conf.reload!
67
+
68
+ # infer some variables
69
+ opts = cli.config.merge({
70
+ fqdn: Socket.gethostbyname(Socket.gethostname).first
71
+ })
72
+
73
+ # sneak in opts without subclassing
74
+ cls.allocate.tap do |obj|
75
+ obj.define_singleton_method(:opts) { opts }
76
+ obj.send(:initialize)
77
+ end
78
+ end
79
+
80
+ end
@@ -0,0 +1,158 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+ require 'set'
5
+
6
+ require 'liquid/ext/hash'
7
+ require 'liquid/ext/ordered_set'
8
+ require 'liquid/environment'
9
+
10
+ ##
11
+ # A {Configuration} consists of one or more Sections. A section is a hash-like
12
+ # object that responds to all keys in the hash as if they were methods:
13
+ #
14
+ # > s = Section.from_hash({:v1 => 2, :nested => {:v2 => 1}})
15
+ # > s.v1
16
+ # => 2
17
+ # > s.nested.v2
18
+ # => 1
19
+ #
20
+ class Section < Hash
21
+
22
+ class << self
23
+
24
+ # How to handle nil values in the configuration?
25
+ #
26
+ # Possible values are:
27
+ # - :nil, nil (return nil)
28
+ # - :raise (raise an exception)
29
+ # - :section (return a NilSection which can be chained)
30
+ #
31
+ attr_accessor :nil_action
32
+
33
+ # Create a new section from the given hash-like object.
34
+ #
35
+ # @param [Hash] hsh The hash to convert into a section.
36
+ # @return [Section] The new {Section} object.
37
+ def from_hash(hsh)
38
+ new.tap do |result|
39
+ hsh.each do |key, value|
40
+ result[key.to_sym] = from_value(value)
41
+ end
42
+ end
43
+ end
44
+
45
+ # Convert the given value into a Section, list of Sections or the pure
46
+ # value. Used to recursively build the Section hash.
47
+ #
48
+ # @private
49
+ def from_value(value)
50
+ case value
51
+ when Hash
52
+ from_hash(value)
53
+ when Array
54
+ value.map do |item|
55
+ from_value(item)
56
+ end
57
+ else
58
+ value
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ # @private
65
+ def method_missing(name, *args)
66
+ if name.to_s =~ /(.*)=$/
67
+ self[$1.to_sym] = Section.from_value(args.first)
68
+ else
69
+ value = self[name]
70
+ self[name] = value.call if value.is_a?(Proc)
71
+ self[name]
72
+ end
73
+ end
74
+ end
75
+
76
+ ##
77
+ # The Configuration class provides a simple interface to configuration stored
78
+ # inside of YAML files.
79
+ #
80
+ class Configuration < Section
81
+
82
+ DEFAULTS = {
83
+ generic: {
84
+ log_backend: :stdout,
85
+ log_caller: false,
86
+ log_level: :info,
87
+ log_format: "%{time} %{progname}(%{pid}) [%{severity}] %{msg}\n",
88
+ log4j_format: "%d %c(%t) [%p] %m%n",
89
+ },
90
+ production: {
91
+ log_format: "%{msg}\n",
92
+ log4j_format: "%m%n",
93
+ },
94
+ staging: {
95
+ log_format: "%{msg}\n",
96
+ log4j_format: "%m%n",
97
+ },
98
+ }
99
+
100
+ # Create a new {Configuration} object.
101
+ #
102
+ # @yield [config] The new configuration object.
103
+ def initialize
104
+ @mixins = OrderedSet.new
105
+ @callbacks = []
106
+ mixin(DEFAULTS)
107
+ end
108
+
109
+ # Mixin a configuration snippet into the current section.
110
+ #
111
+ # @param [Hash, String] value A hash to merge into the current
112
+ # configuration. If a string is given a filename
113
+ # is assumed and the given file is expected to
114
+ # contain a YAML hash.
115
+ # @return [void]
116
+ def mixin(value)
117
+ @mixins << value
118
+
119
+ if value.is_a?(String)
120
+ value = YAML.load(File.read(value))
121
+ end
122
+
123
+ return unless value
124
+
125
+ value = Section.from_hash(value)
126
+
127
+ deep_merge!(value[:generic]) if value.has_key?(:generic)
128
+
129
+ if value.has_key?(Env.to_sym)
130
+ deep_merge!(value[Env.to_sym])
131
+ else
132
+ deep_merge!(value)
133
+ end
134
+ end
135
+
136
+ # Reload all mixins.
137
+ #
138
+ # @return [void]
139
+ def reload!
140
+ clear
141
+
142
+ @mixins.each do |file|
143
+ mixin(file)
144
+ end
145
+
146
+ @callbacks.each do |callback|
147
+ callback.call(self)
148
+ end
149
+ end
150
+
151
+ # Register a callback for config mixins.
152
+ #
153
+ # @return [void]
154
+ def callback(&block)
155
+ @callbacks << block
156
+ end
157
+
158
+ end
@@ -0,0 +1,67 @@
1
+ ##
2
+ # A simple convenience class to support multiple environments in which a
3
+ # program can run (e.g. development, production, etc).
4
+ #
5
+ class Environment
6
+ attr_accessor :key
7
+
8
+ # Create a new Environment instance with the corresponding +key+ in the +ENV+
9
+ # hash.
10
+ #
11
+ # @param [String] key The key in +ENV+ to contain the current program
12
+ # environment.
13
+ #
14
+ def initialize(key = "RACK_ENV")
15
+ @key = key
16
+ end
17
+
18
+ # Retreive the current environment mode.
19
+ #
20
+ # @return [String] The current environment mode.
21
+ def mode
22
+ ENV[@key] || 'development'
23
+ rescue
24
+ 'development'
25
+ end
26
+
27
+ # Retrieve the current environment mode and convert it to a symbol.
28
+ #
29
+ # @return [Symbol] The current environment mode.
30
+ def to_sym
31
+ mode.to_sym
32
+ end
33
+
34
+ # Return true if the current environment is +production+.
35
+ def production?
36
+ to_sym == :production
37
+ end
38
+
39
+ alias :prod? :production?
40
+
41
+ # Return true if the current environment is +production+.
42
+ def staging?
43
+ to_sym == :staging
44
+ end
45
+
46
+ # Return true if the current environment is +development+.
47
+ def development?
48
+ to_sym == :development
49
+ end
50
+
51
+ alias :dev? :development?
52
+
53
+ # Return true if the current environment is +test+.
54
+ def test?
55
+ to_sym == :test
56
+ end
57
+
58
+ # Set the environment mode.
59
+ #
60
+ # @param [String] The new environment mode.
61
+ def set(value)
62
+ ENV[@key] = value.to_s
63
+ end
64
+ end
65
+
66
+ # Global instance of {Environment}.
67
+ Env = Environment.new
@@ -0,0 +1,23 @@
1
+ class Array
2
+
3
+ def pick(n=1)
4
+ Array.new(n) { self[Kernel::rand(size)-1] }
5
+ end
6
+
7
+ def pick_one
8
+ self[Kernel::rand(size)-1]
9
+ end
10
+
11
+ def to_h(&block)
12
+ Hash[*self.map { |v| [v, block.call(v)] }.flatten]
13
+ end
14
+
15
+ def / parts
16
+ inject([[]]) do |ary, x|
17
+ ary << [] if [*ary.last].nitems == length / parts
18
+ ary.last << x
19
+ ary
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,20 @@
1
+ require 'active_support/core_ext/enumerable'
2
+
3
+ module Enumerable
4
+ def mean
5
+ sum.to_f / length
6
+ end
7
+
8
+ def variance
9
+ m = mean
10
+ reduce(0) {|accum, item| accum + (item - m) ** 2}.to_f / (length - 1)
11
+ end
12
+
13
+ def stdev
14
+ Math.sqrt(variance)
15
+ end
16
+
17
+ def percentile(pc)
18
+ sort[(pc * length).ceil - 1]
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ ##
2
+ # Various Hash extensions.
3
+ #
4
+ class Hash
5
+
6
+ # Recursively merge +other_hash+ into +self+ and return the new hash.
7
+ def deep_merge(other_hash)
8
+ self.merge(other_hash) do |key, oldval, newval|
9
+ oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
10
+ newval = newval.to_hash if newval.respond_to?(:to_hash)
11
+ oldval.is_a?(Hash) && newval.is_a?(Hash) ? oldval.deep_merge(newval) : newval
12
+ end
13
+ end
14
+
15
+ # Recursively merge and replace +other_hash+ into +self+.
16
+ def deep_merge!(other_hash)
17
+ replace(deep_merge(other_hash))
18
+ end
19
+
20
+ # accumulate existing keys from +other_hash+ into +self+.
21
+ def delta_merge!(other_hash)
22
+ other_hash.each do |k,v|
23
+ if self.has_key?(k)
24
+ self[k] += v
25
+ else
26
+ self[k] = v
27
+ end
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,5 @@
1
+ class NilClass
2
+ def empty?
3
+ true
4
+ end
5
+ end
@@ -0,0 +1,49 @@
1
+ module Memory
2
+ WORD_SIZE = 8
3
+ OBJ_SIZE = 40 # some are smaller
4
+ OBJ_OVERHEAD = WORD_SIZE + OBJ_SIZE
5
+
6
+ def self.size(obj)
7
+ return WORD_SIZE if obj.is_a?(Fixnum)
8
+
9
+ case obj
10
+ when String
11
+ obj.size
12
+ when Array
13
+ obj.size * WORD_SIZE
14
+ when Hash
15
+ obj.size * WORD_SIZE * 2
16
+ #when Enumerable
17
+ # result = 0
18
+ # obj.each do |ref|
19
+ # result += WORD_SIZE
20
+ # end
21
+ # result
22
+ else
23
+ 0
24
+ end + OBJ_OVERHEAD
25
+ rescue => e
26
+ puts "failed to get object size for #{obj.inspect}: #{e}"
27
+ return OBJ_OVERHEAD
28
+ end
29
+ end
30
+
31
+ module ObjectSpace
32
+ def self.memory_stats(*args)
33
+ stats = {}
34
+
35
+ self.each_object do |obj|
36
+ stats[obj.class] ||= []
37
+ stats[obj.class] << Memory.size(obj)
38
+ end
39
+
40
+ stats.map do |cls, sizes|
41
+ cnt = sizes.length
42
+ sum = sizes.reduce(:+)
43
+ avg = sum / cnt
44
+ [cls, [cnt, avg, sum]]
45
+ end.sort_by do |cls, sizes|
46
+ sizes[2]
47
+ end.reverse
48
+ end
49
+ end
@@ -0,0 +1,10 @@
1
+ # http://stackoverflow.com/a/8451605/965088
2
+ require 'set'
3
+ require 'active_support/ordered_hash'
4
+
5
+ class OrderedSet < Set
6
+ def initialize enum = nil, &block
7
+ @hash = ActiveSupport::OrderedHash.new
8
+ super
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module Signal
2
+ def self.register_shutdown_handler(&block)
3
+ signals = %w(INT TERM)
4
+
5
+ # The signal QUIT is in use by the JVM itself
6
+ signals << 'QUIT' unless RUBY_PLATFORM == 'java'
7
+
8
+ signals.each do |sig|
9
+ old = trap(sig) {}
10
+ trap(sig) { block.call; old.call }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ class String
2
+ alias each each_line
3
+ end
@@ -0,0 +1,17 @@
1
+ # make default what should be default
2
+ Thread.abort_on_exception = true
3
+
4
+ class Thread
5
+
6
+ def self.name
7
+ Thread.current[:name] || Java::JavaLang::Thread.currentThread.getName
8
+ end
9
+
10
+ def self.name=(value)
11
+ Thread.current[:name] = value
12
+ if RUBY_PLATFORM == "java"
13
+ Java::JavaLang::Thread.currentThread.setName(value)
14
+ end
15
+ end
16
+
17
+ end