madvertise-ext 0.1.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.
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/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use --create ruby-1.9.3-p125@madvertise-ext
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --protected --no-private
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem 'bundler'
7
+ gem 'pry'
8
+ gem 'pry-doc'
9
+ gem 'rake'
10
+ gem 'redcarpet'
11
+ gem 'reek'
12
+ gem 'rspec'
13
+ gem 'ruby2ruby', '=1.3.0' # 1.3.1 is broken :(
14
+ gem 'simplecov'
15
+ gem 'yard'
16
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 madvertise Mobile Advertising GmbH
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Madvertise::Ext
2
+
3
+ The madvertise-ext gem provides a bunch of ruby extensions.
4
+
5
+ [![Build Status](https://secure.travis-ci.org/madvertise/ext.png)](http://travis-ci.org/madvertise/ext)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'madvertise-ext'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install madvertise-ext
20
+
21
+ ## Usage
22
+
23
+ Please refer to the [API documentation](http://rubydoc.info/gems/madvertise-ext/frames).
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/setup"
4
+ require "bundler/gem_tasks"
5
+
6
+ Dir['tasks/**/*.rake'].each { |t| load t }
7
+
8
+ task :default => [:spec]
@@ -0,0 +1,174 @@
1
+ require 'yaml'
2
+ require 'madvertise/ext/hash'
3
+
4
+ ##
5
+ # A {Configuration} consists of one or more Sections. A section is a hash-like
6
+ # object that responds to all keys in the hash as if they were methods:
7
+ #
8
+ # > s = Section.from_hash({:v1 => 2, :nested => {:v2 => 1}})
9
+ # > s.v1
10
+ # => 2
11
+ # > s.nested.v2
12
+ # => 1
13
+ #
14
+ class Section < Hash
15
+ class << self
16
+
17
+ # Create a new section from the given hash-like object.
18
+ #
19
+ # @param [Hash] hsh The hash to convert into a section.
20
+ # @return [Section] The new {Section} object.
21
+ def from_hash(hsh)
22
+ result = new.tap do |result|
23
+ hsh.each do |key, value|
24
+ result[key.to_sym] = from_value(value)
25
+ end
26
+ end
27
+ end
28
+
29
+ # Convert the given value into a Section, list of Sections or the pure
30
+ # value. Used to recursively build the Section hash.
31
+ #
32
+ # @private
33
+ def from_value(value)
34
+ case value
35
+ when Hash
36
+ from_hash(value)
37
+ when Array
38
+ value.map do |item|
39
+ from_hash(item)
40
+ end
41
+ else
42
+ value
43
+ end
44
+ end
45
+ end
46
+
47
+ # Mixin a configuration snippet into the current section.
48
+ #
49
+ # @param [Hash, String] value A hash to merge into the current
50
+ # configuration. If a string is given a filename
51
+ # is assumed and the given file is expected to
52
+ # contain a YAML hash.
53
+ # @return [void]
54
+ def mixin(value)
55
+ unless value.is_a?(Hash)
56
+ value = Section.from_hash(YAML.load(File.read(value)))
57
+ end
58
+
59
+ self.deep_merge!(value[:default]) if value.has_key?(:default)
60
+ self.deep_merge!(value[:generic]) if value.has_key?(:generic)
61
+
62
+ if value.has_key?(@mode)
63
+ self.deep_merge!(value[@mode])
64
+ else
65
+ self.deep_merge!(value)
66
+ end
67
+ end
68
+
69
+ # Build the call chain including NilSections.
70
+ #
71
+ # @private
72
+ def method_missing(name, *args)
73
+ if name.to_s =~ /(.*)=$/
74
+ self[$1.to_sym] = Section.from_value(args.first)
75
+ else
76
+ value = self[name]
77
+ value = value.call if value.is_a?(Proc)
78
+ value = NilSection.new if value.nil?
79
+ self[name] = value
80
+ end
81
+ end
82
+ end
83
+
84
+ ##
85
+ # The Configuration class provides a simple interface to configuration stored
86
+ # inside of YAML files.
87
+ #
88
+ class Configuration < Section
89
+
90
+ # Create a new {Configuration} object.
91
+ #
92
+ # @param [Symbol] mode The mode to load from the configurtion file
93
+ # (production, development, etc)
94
+ # @yield [config] The new configuration object.
95
+ def initialize(mode = :development)
96
+ @mode = mode
97
+ yield self if block_given?
98
+ end
99
+
100
+ # Load given mixins from +path+.
101
+ #
102
+ # @param [String] path The path to mixin files.
103
+ # @param [Array] mixins_to_use A list of mixins to load from +path+.
104
+ # @return [void]
105
+ def load_mixins(path, mixins_to_use)
106
+ mixins_to_use.map do |mixin_name|
107
+ File.join(path, "#{mixin_name}.yml")
108
+ end.each do |mixin_file|
109
+ mixin(mixin_file)
110
+ end
111
+ end
112
+
113
+ ##
114
+ # The {Helpers} module can be included in all classes that wish to load
115
+ # configuration file(s). In order to load custom configuration files the
116
+ # including class needs to set the +@config_file+ instance variable.
117
+ #
118
+ module Helpers
119
+
120
+ # Load the configuration. The default configuration is located at
121
+ # +lib/ganymed/config.yml+ inside the Ganymed source tree.
122
+ #
123
+ # @return [Configuration] The configuration object. See madvertise-ext gem
124
+ # for details.
125
+ def config
126
+ @config ||= Configuration.new(Env.mode) do |config|
127
+ config.mixin(@default_config_file) if @default_config_file
128
+ config.mixin(@config_file) if @config_file
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ ##
135
+ # A NilSection is returned for all missing/empty values in the config file. This
136
+ # allows for terse code when accessing values that have not been configured by
137
+ # the user.
138
+ #
139
+ # Consider code like this:
140
+ #
141
+ # config.server.listen.tap do |listen|
142
+ # open_socket(listen.host, listen.port)
143
+ # end
144
+ #
145
+ # Given that your server component is optional and does not appear in the
146
+ # configuration file at all, +config.server.listen+ will return a NilSection
147
+ # that does not call the block given to tap _at all_.
148
+ #
149
+ class NilSection
150
+ # @return true
151
+ def nil?
152
+ true
153
+ end
154
+
155
+ # @return true
156
+ def empty?
157
+ true
158
+ end
159
+
160
+ # @return false
161
+ def present?
162
+ false
163
+ end
164
+
165
+ # @return self
166
+ def tap
167
+ self
168
+ end
169
+
170
+ # @private
171
+ def method_missing(*args, &block)
172
+ self
173
+ end
174
+ end
@@ -0,0 +1,22 @@
1
+ module Enumerable
2
+ def sum
3
+ reduce(:+)
4
+ end
5
+
6
+ def mean
7
+ sum.to_f / length
8
+ end
9
+
10
+ def variance
11
+ m = mean
12
+ reduce(0) {|accum, item| accum + (item - m) ** 2}.to_f / (length - 1)
13
+ end
14
+
15
+ def stdev
16
+ Math.sqrt(variance)
17
+ end
18
+
19
+ def percentile(pc)
20
+ sort[(pc * length).ceil - 1]
21
+ end
22
+ end
@@ -0,0 +1,56 @@
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=nil)
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
+ end
24
+
25
+ # Retrieve the current environment mode and convert it to a symbol.
26
+ #
27
+ # @return [Symbol] The current environment mode.
28
+ def to_sym
29
+ mode.to_sym
30
+ end
31
+
32
+ # Return true if the current environment is +production+.
33
+ def prod?
34
+ to_sym == :production
35
+ end
36
+
37
+ # Return true if the current environment is +development+.
38
+ def dev?
39
+ to_sym == :development
40
+ end
41
+
42
+ # Return true if the current environment is +test+.
43
+ def test?
44
+ to_sym == :test
45
+ end
46
+
47
+ # Set the environment mode.
48
+ #
49
+ # @param [String] The new environment mode.
50
+ def set(value)
51
+ ENV[@key] = value.to_s
52
+ end
53
+ end
54
+
55
+ # Global instance of {Environment}.
56
+ Env = Environment.new
@@ -0,0 +1,20 @@
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
+ end
@@ -0,0 +1,38 @@
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
+ require 'madvertise/ext/environment'
3
+ require 'madvertise-logging'
4
+
5
+ include Madvertise::Logging
6
+
7
+ ##
8
+ # The {Logging} module provides a global container for the logger object.
9
+ #
10
+ module Logging
11
+ mattr_accessor :logger
12
+ self.logger = nil
13
+
14
+ # @private
15
+ def self.create_logger
16
+ if Env.prod?
17
+ ImprovedLogger.new(:syslog, $0)
18
+ else
19
+ ImprovedLogger.new(STDERR, $0)
20
+ end.tap do |logger|
21
+ logger.level = :info
22
+ end
23
+ end
24
+
25
+ ##
26
+ # The {Logging::Helpers} module can be included in classes that wish to use
27
+ # the global logger.
28
+ #
29
+ module Helpers
30
+
31
+ # Retreive and possibly create the global logger object.
32
+ #
33
+ # @return [Logger] The logger object.
34
+ def log
35
+ Logging.logger ||= Logging.create_logger
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ ---
2
+ NestedIterators:
3
+ exclude:
4
+ - Section#from_hash
5
+ FeatureEnvy:
6
+ exclude:
7
+ - Hash#deep_merge
@@ -0,0 +1,6 @@
1
+ # @private
2
+ module Madvertise
3
+ module Ext
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/madvertise/ext/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = "madvertise-ext"
6
+ gem.version = Madvertise::Ext::VERSION
7
+ gem.authors = ["Benedikt Böhm"]
8
+ gem.email = ["benedikt.boehm@madvertise.com"]
9
+ gem.description = %q{Ruby extensions}
10
+ gem.summary = %q{Ruby extensions}
11
+ gem.homepage = "https://github.com/madvertise/ext"
12
+
13
+ gem.add_dependency "madvertise-logging"
14
+
15
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ gem.files = `git ls-files`.split("\n")
17
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ gem.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'madvertise/ext/enumerable'
3
+
4
+ describe Enumerable do
5
+
6
+ it "should support the sum for a list of numbers" do
7
+ [1,2,3,4,5].sum.should == 15
8
+ end
9
+
10
+ it "should support the mean for a list of numbers" do
11
+ [1,2,3,4,5].mean.should == 3.0
12
+ end
13
+
14
+ it "should support the variance for a list of numbers" do
15
+ [9,8,7,6,5].variance.should == 2.5
16
+ end
17
+
18
+ it "should support the standard deviation for a list of numbers" do
19
+ [9,8,7,6,5].stdev.should == 1.5811388300841898
20
+ end
21
+
22
+ it "should support a percentile method for a list of numbers" do
23
+ [9,1,8,2,7,3,6,4,5,4,3,2,1].percentile(0.9).should == 8
24
+ end
25
+
26
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+
4
+ require 'simplecov'
5
+ SimpleCov.start
6
+
7
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
8
+ #require 'madvertise-ext'
9
+
10
+ RSpec.configure do |config|
11
+ # == Mock Framework
12
+ #
13
+ # RSpec uses it's own mocking framework by default. If you prefer to
14
+ # use mocha, flexmock or RR, uncomment the appropriate line:
15
+ #
16
+ # config.mock_with :mocha
17
+ # config.mock_with :flexmock
18
+ # config.mock_with :rr
19
+ end
data/tasks/reek.rake ADDED
@@ -0,0 +1,5 @@
1
+ require 'reek/rake/task'
2
+
3
+ Reek::Rake::Task.new do |t|
4
+ t.fail_on_error = false
5
+ end
data/tasks/rspec.rake ADDED
@@ -0,0 +1,7 @@
1
+ require 'rspec'
2
+ require 'rspec/core/rake_task'
3
+
4
+ desc "Run the specs"
5
+ RSpec::Core::RakeTask.new do |t|
6
+ t.rspec_opts = ['--options', "spec/spec.opts"]
7
+ end
data/tasks/yard.rake ADDED
@@ -0,0 +1,5 @@
1
+ require 'yard'
2
+
3
+ YARD::Rake::YardocTask.new do |t|
4
+ t.files = ['lib/**/*.rb', 'README.rdoc']
5
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: madvertise-ext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Benedikt Böhm
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: madvertise-logging
16
+ requirement: &12312600 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *12312600
25
+ description: Ruby extensions
26
+ email:
27
+ - benedikt.boehm@madvertise.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .gitignore
33
+ - .rvmrc
34
+ - .travis.yml
35
+ - .yardopts
36
+ - Gemfile
37
+ - LICENSE
38
+ - README.md
39
+ - Rakefile
40
+ - lib/madvertise/ext/config.rb
41
+ - lib/madvertise/ext/enumerable.rb
42
+ - lib/madvertise/ext/environment.rb
43
+ - lib/madvertise/ext/hash.rb
44
+ - lib/madvertise/ext/logging.rb
45
+ - lib/madvertise/ext/mask.reek
46
+ - lib/madvertise/ext/version.rb
47
+ - madvertise-ext.gemspec
48
+ - spec/enumerable_spec.rb
49
+ - spec/spec.opts
50
+ - spec/spec_helper.rb
51
+ - tasks/reek.rake
52
+ - tasks/rspec.rake
53
+ - tasks/yard.rake
54
+ homepage: https://github.com/madvertise/ext
55
+ licenses: []
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ segments:
67
+ - 0
68
+ hash: 3585342747307682113
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ segments:
76
+ - 0
77
+ hash: 3585342747307682113
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 1.8.17
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Ruby extensions
84
+ test_files:
85
+ - spec/enumerable_spec.rb
86
+ - spec/spec.opts
87
+ - spec/spec_helper.rb
88
+ has_rdoc: