unpatched 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/License ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Konstantin Haase
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,62 @@
1
+ Convenience library, like ActiveSupport or extlib, but without a single
2
+ monkey-patch. It is also an API experiment.
3
+
4
+ # Usage
5
+
6
+ Stand alone:
7
+
8
+ ``` ruby
9
+ require 'unpatched'
10
+ inlcude Unpatched
11
+
12
+ like("FooBar").but.underscore!
13
+ about(1).month.and(4).days.ago!
14
+ ```
15
+
16
+ Is that too much sugar? Try this:
17
+
18
+ ``` ruby
19
+ require 'unpatched'
20
+ include Unpatched::Unfancy
21
+ _('FooBar').underscore!
22
+ ```
23
+
24
+ Still too much?
25
+
26
+ ``` ruby
27
+ require 'unpatched'
28
+ Unpatched['FooBar'].underscore!
29
+ ```
30
+
31
+ With Sinatra:
32
+
33
+ ``` ruby
34
+ require 'sinatra'
35
+ require 'unpatched'
36
+ helpers Unpatched
37
+
38
+ get '/' do
39
+ expires exactly(1.5).minutes.from_now!
40
+ "Hey, ho, let's go!"
41
+ end
42
+ ```
43
+
44
+ # When to use an exclamation mark
45
+
46
+ Short: You don't have to. But methods without one will always return magically
47
+ enhanced objects. Since you never want to pass those on (otherwise, what's the
48
+ point?), you can get vanilla objects by using an exclamation mark.
49
+
50
+ Rule of thumb: Use it at the end of your method chain.
51
+
52
+ # Installation
53
+
54
+ gem install unpatched
55
+
56
+ # TODO
57
+
58
+ * Write code and documentation
59
+ * Fix project description in gemspec
60
+ * Change testing framework if necessary (see Rakefile, currently RSpec)
61
+ * Adjust unpatched.gemspec if your github name is not rkh
62
+ * Adjust License if your real name is not Konstantin Haase
@@ -0,0 +1,37 @@
1
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
2
+
3
+ begin
4
+ require 'bundler'
5
+ Bundler::GemHelper.install_tasks
6
+ rescue LoadError => e
7
+ $stderr.puts e
8
+ end
9
+
10
+ desc "run specs"
11
+ task(:spec) { ruby '-S rspec spec' }
12
+
13
+ desc "generate gemspec"
14
+ task 'unpatched.gemspec' do
15
+ require 'unpatched/version'
16
+ content = File.read 'unpatched.gemspec'
17
+
18
+ fields = {
19
+ :authors => `git shortlog -sn`.scan(/[^\d\s].*/),
20
+ :email => `git shortlog -sne`.scan(/[^<]+@[^>]+/),
21
+ :files => `git ls-files`.split("\n").reject { |f| f =~ /^(\.|Gemfile)/ }
22
+ }
23
+
24
+ fields.each do |field, values|
25
+ updated = " s.#{field} = ["
26
+ updated << values.map { |v| "\n %p" % v }.join(',')
27
+ updated << "\n ]"
28
+ content.sub!(/ s\.#{field} = \[\n( .*\n)* \]/, updated)
29
+ end
30
+
31
+ content.sub! /(s\.version.*=\s+).*/, "\\1\"#{Unpatched::VERSION}\""
32
+ File.open('unpatched.gemspec', 'w') { |f| f << content }
33
+ end
34
+
35
+ task :gemspec => 'unpatched.gemspec'
36
+ task :default => :spec
37
+ task :test => :spec
@@ -0,0 +1,168 @@
1
+ require 'unpatched/version'
2
+
3
+ module Unpatched
4
+ MINUTE = 60
5
+ HOUR = 60 * MINUTE
6
+ DAY = 24 * HOUR
7
+ MONTH = 30 * DAY
8
+ YEAR = 365 * DAY
9
+
10
+ module Utils
11
+ extend self
12
+
13
+ def wrapped(value)
14
+ NormalWrapper.new(value)
15
+ end
16
+
17
+ def unwrapped(value)
18
+ value = value.__instance_eval__ { @value } while Wrapper === value
19
+ value
20
+ end
21
+
22
+ def numeric(value)
23
+ case value
24
+ when Numeric then value
25
+ when Wrapper then numeric unwrapped(value)
26
+ else
27
+ begin
28
+ Integer value
29
+ rescue ArgumentError
30
+ Float value
31
+ end
32
+ end
33
+ end
34
+
35
+ alias num numeric
36
+ end
37
+
38
+ class Wrapper < defined?(BasicObject) ? BasicObject : Object
39
+ def self.const_missing(const) ::Unpatched.const_get(const) end
40
+ alias __instance_eval__ instance_eval
41
+
42
+ if superclass == Object
43
+ instance_methods.each do |m|
44
+ undef_method(m) if m.to_s !~ /(?:^__|^send$|^object_id$)/
45
+ end
46
+ else
47
+ undef ==
48
+ undef equal?
49
+ undef instance_eval
50
+ end
51
+
52
+ def initialize(value)
53
+ @value = Utils.unwrapped(value)
54
+ end
55
+
56
+ def inspect
57
+ @value.inspect
58
+ end
59
+
60
+ def and(value = (undefined = true))
61
+ return self if undefined
62
+ if Wrapper === value
63
+ Utils.wrapped @value + unwrapped(value)
64
+ else
65
+ MultiWrapper.new self, value
66
+ end
67
+ end
68
+
69
+ alias_method :but, :and
70
+ end
71
+
72
+ class MultiWrapper < Wrapper
73
+ def initialize(base, value)
74
+ @base, @value = base, Utils.wrapped(value)
75
+ end
76
+
77
+ private
78
+ def method_missing(*a, &b)
79
+ @base + @value.__send__(*a, &b)
80
+ end
81
+ end
82
+
83
+ class NormalWrapper < Wrapper
84
+ def second
85
+ value = Utils.unwrapped @value
86
+ if value.respond_to? :second
87
+ value.second
88
+ else
89
+ Utils.wrapped Utils.num(value)
90
+ end
91
+ rescue TypeError, ArgumentError => err
92
+ raise err unless value.respond_to? :[]
93
+ value[1]
94
+ end
95
+
96
+ def underscore
97
+ to_s.
98
+ gsub(/::/, '/').
99
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
100
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
101
+ tr("-", "_").
102
+ downcase
103
+ end
104
+
105
+ def seconds; Utils.wrapped Utils.num(@value) end
106
+ def minute; Utils.wrapped Utils.num(@value) * MINUTE end
107
+ def hour; Utils.wrapped Utils.num(@value) * HOUR end
108
+ def day; Utils.wrapped Utils.num(@value) * DAY end
109
+ def month; Utils.wrapped Utils.num(@value) * MONTH end
110
+ def year; Utils.wrapped Utils.num(@value) * YEAR end
111
+
112
+ def before(other)
113
+ Utils.wrapped Utils.unwrapped(other) - @value
114
+ end
115
+
116
+ def after(other)
117
+ Utils.wrapped Utils.unwrapped(other) + @value
118
+ end
119
+
120
+ def ago
121
+ before Time.now
122
+ end
123
+
124
+
125
+ def from_now
126
+ after Time.now
127
+ end
128
+
129
+ alias minutes minute
130
+ alias hours hour
131
+ alias days day
132
+ alias months month
133
+ alias years year
134
+
135
+ private
136
+
137
+ def method_missing(m, *a, &b)
138
+ a.map! { |e| Utils.unwrapped e }
139
+ if m[-1] == ?! and NormalWrapper.method_defined?(method = m[0..-2])
140
+ result = __send__(method, *a, &b)
141
+ Utils.unwrapped result
142
+ else
143
+ Utils.wrapped @value.__send__(m, *a, &b)
144
+ end
145
+ end
146
+ end
147
+
148
+ module Unfancy
149
+ private
150
+ def _(value)
151
+ Utils.wrapped(value)
152
+ end
153
+ end
154
+
155
+ module Fancy
156
+ include Unfancy
157
+ %w[about exactly like is some].each do |meth|
158
+ alias_method meth, :_
159
+ private meth
160
+ end
161
+ end
162
+
163
+ def self.[](value)
164
+ Utils.wrapped(value)
165
+ end
166
+
167
+ include Fancy
168
+ end
@@ -0,0 +1,42 @@
1
+ module Unpatched
2
+ def self.version
3
+ VERSION
4
+ end
5
+
6
+ module VERSION
7
+ extend Comparable
8
+
9
+ MAJOR = 0
10
+ MINOR = 0
11
+ TINY = 1
12
+ SIGNATURE = [MAJOR, MINOR, TINY]
13
+ STRING = SIGNATURE.join '.'
14
+
15
+ def self.major; MAJOR end
16
+ def self.minor; MINOR end
17
+ def self.tiny; TINY end
18
+ def self.to_s; STRING end
19
+
20
+ def self.hash
21
+ STRING.hash
22
+ end
23
+
24
+ def self.<=>(other)
25
+ other = other.split('.').map { |i| i.to_i } if other.respond_to? :split
26
+ SIGNATURE <=> Array(other)
27
+ end
28
+
29
+ def self.inspect
30
+ STRING.inspect
31
+ end
32
+
33
+ def self.respond_to?(meth, *)
34
+ meth.to_s !~ /^__|^to_str$/ and STRING.respond_to? meth unless super
35
+ end
36
+
37
+ def self.method_missing(meth, *args, &block)
38
+ return super unless STRING.respond_to?(meth)
39
+ STRING.send(meth, *args, &block)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,14 @@
1
+ require 'unpatched'
2
+
3
+ describe Unpatched do
4
+ before { extend Unpatched }
5
+ it 'should not fail me' do
6
+ exactly(2).seconds.should == 2
7
+ exactly(2).minutes.should == 120
8
+ about(10).minutes.and(1).second.should == 601
9
+ _('FooBar').underscore.should == 'foo_bar'
10
+ about(10).minutes.ago!.should be_a(Time)
11
+ about(10).minutes.from_now!.should be_a(Time)
12
+ exactly(10).before(12).should == 2
13
+ end
14
+ end
@@ -0,0 +1,33 @@
1
+ # Run `rake unpatched.gemspec` to update the gemspec.
2
+ Gem::Specification.new do |s|
3
+ # general infos
4
+ s.name = "unpatched"
5
+ s.version = "0.0.1"
6
+ s.description = "Convenience library without a single monkey-patch."
7
+ s.homepage = "http://github.com/rkh/unpatched"
8
+ s.summary = s.description
9
+
10
+ # generated from git shortlog -sn
11
+ s.authors = [
12
+ "Konstantin Haase"
13
+ ]
14
+
15
+ # generated from git shortlog -sne
16
+ s.email = [
17
+ "konstantin.mailinglists@googlemail.com"
18
+ ]
19
+
20
+ # generated from git ls-files
21
+ s.files = [
22
+ "License",
23
+ "README.md",
24
+ "Rakefile",
25
+ "lib/unpatched.rb",
26
+ "lib/unpatched/version.rb",
27
+ "spec/unpatched_spec.rb",
28
+ "unpatched.gemspec"
29
+ ]
30
+
31
+ # dependencies
32
+ s.add_development_dependency "rspec", "~> 2.0"
33
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unpatched
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Konstantin Haase
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-05-31 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: &2153180300 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '2.0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2153180300
26
+ description: Convenience library without a single monkey-patch.
27
+ email:
28
+ - konstantin.mailinglists@googlemail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - License
34
+ - README.md
35
+ - Rakefile
36
+ - lib/unpatched.rb
37
+ - lib/unpatched/version.rb
38
+ - spec/unpatched_spec.rb
39
+ - unpatched.gemspec
40
+ has_rdoc: true
41
+ homepage: http://github.com/rkh/unpatched
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.6.2
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Convenience library without a single monkey-patch.
65
+ test_files: []