liquid-ext 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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