attach_function 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 184c80c899df350d373fb5f60ddbc995a379a8f2
4
+ data.tar.gz: f02923c5fd1d28b228034f713d5742fde4c4d400
5
+ SHA512:
6
+ metadata.gz: dcbd1c3e00246c42483b3084afc9d8d799af97fcff6771e884d7c79cd422da282d906971a85d83199604330b069671aa4d572c825095aa964d738cd5a65cf7dd
7
+ data.tar.gz: 473b3497787bfd6bf5ae9b4362e3f9981018c0a9ddd09cd682bf495144ca8fff4a49f4dec3b66cc79c26acd225b2b6cf580ee0229a894a3e247910fab5141333
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,53 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec feature)
6
+
7
+ ## Uncomment to clear the screen before every task
8
+ # clearing :on
9
+
10
+ ## Guard internally checks for changes in the Guardfile and exits.
11
+ ## If you want Guard to automatically start up again, run guard in a
12
+ ## shell loop, e.g.:
13
+ ##
14
+ ## $ while bundle exec guard; do echo "Restarting Guard..."; done
15
+ ##
16
+ ## Note: if you are using the `directories` clause above and you are not
17
+ ## watching the project directory ('.'), the you will want to move the Guardfile
18
+ ## to a watched dir and symlink it back, e.g.
19
+ #
20
+ # $ mkdir config
21
+ # $ mv Guardfile config/
22
+ # $ ln -s config/Guardfile .
23
+ #
24
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
25
+
26
+ # Note: The cmd option is now required due to the increasing number of ways
27
+ # rspec may be run, below are examples of the most common uses.
28
+ # * bundler: 'bundle exec rspec'
29
+ # * bundler binstubs: 'bin/rspec'
30
+ # * spring: 'bin/rspec' (This will use spring if running and you have
31
+ # installed the spring binstubs per the docs)
32
+ # * zeus: 'zeus rspec' (requires the server to be started separately)
33
+ # * 'just' rspec: 'rspec'
34
+
35
+ guard :rspec, cmd: "bundle exec rspec" do
36
+ watch('spec/spec_helper.rb') { "spec" }
37
+ watch(%r{^spec/.+_spec\.rb})
38
+ watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
39
+ end
40
+
41
+
42
+
43
+ guard :bundler do
44
+ require 'guard/bundler'
45
+ require 'guard/bundler/verify'
46
+ helper = Guard::Bundler::Verify.new
47
+
48
+ files = ['Gemfile']
49
+ files += Dir['*.gemspec'] if files.any? { |f| helper.uses_gemspec?(f) }
50
+
51
+ # Assume files are symlinked from somewhere
52
+ files.each { |file| watch(helper.real_path(file)) }
53
+ end
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # AttachFunction
2
+
3
+ AttachFunction defines new methods that are partial applications of a target function where the first argument to the target function gets fixed to self.
4
+
5
+ The name of the newly defined method will be the basename of the target function (the module path gets stripped) or a user-specified name.
6
+ The receiver of relatively specified parameter functions will be the current module, if a user-specified name is given and
7
+ the user-specified name is not the same as the basename of the target function, or the enclosing module, if no-user specified name is provided or
8
+ if the user-specified name is the same as the basename of the parameter.
9
+
10
+ ## Usage Example:
11
+
12
+ require 'attach_function'
13
+
14
+ module Math
15
+
16
+ #This will contain the method versions of the functions defined in the Math module
17
+ module MethodVersions
18
+ #Get the attach_function macro
19
+ extend AttachFunction
20
+ #Apply it to all methods of the Math module that aren't Object methods
21
+ (Math.methods - Object.methods).each do |m|
22
+ puts "Attaching #{m}"
23
+ attach_function m
24
+ end
25
+ end
26
+ end
27
+
28
+ #Now we include the Math::MethodVersions in Numeric
29
+ Numeric.include(Math::MethodVersions)
30
+ #And now we can do this:
31
+ p "3.14.sin = #{3.14.sin}"
32
+ p "10.log = #{10.log10}"
33
+ p "4.sqrt = #{4.sqrt}"
34
+
35
+ #The functionality that has been added to Numeric in this way is contained in the Math::MethodVersions mixin.
36
+ #I consider this much nicer than rudely monkepatching methods right onto a core class.
37
+ #This way, library users can see (in pry, for example, or via introspection) where a certain added method came from, and possibly filter it out.
38
+ #(Ruby doesn't currently support unmixing).
39
+
40
+
41
+ See the specs and the example folder for more examples.
42
+ ## Installation
43
+
44
+ Add this line to your application's Gemfile:
45
+
46
+ ```ruby
47
+ gem 'attach_function'
48
+ ```
49
+
50
+ And then execute:
51
+
52
+ $ bundle
53
+
54
+ Or install it yourself as:
55
+
56
+ $ gem install attach_function
57
+
58
+ ## Usage
59
+
60
+ User it in any way you like.
61
+
62
+ ## Contributing
63
+
64
+ 1. Fork it ( https://github.com/[my-github-username]/i_rewriter/fork )
65
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
66
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
67
+ 4. Push to the branch (`git push origin my-new-feature`)
68
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'ostruct'
6
+
7
+ gem = OpenStruct.new
8
+ gem.name = File.basename(File.dirname(__FILE__))
9
+ require "#{gem.name}/version"
10
+ gem.module = AttachFunction
11
+
12
+ Gem::Specification.new do |spec|
13
+
14
+ spec.name = gem.name
15
+ spec.version = (gem.module)::VERSION
16
+ spec.summary = %q{True in-place file-editing}
17
+ spec.description = %q{True in-place file-editing (i.e, inode(input) == inode(output)) like with sed, awk, or `ruby i -{p|n}e`, but truly in-place}
18
+
19
+ spec.authors = ["Petr Skocik"]
20
+ spec.email = ["pskocik@gmail.com"]
21
+ spec.homepage = "https://github.com/pjump/#{spec.name}.git"
22
+ spec.licenses = %w[gplv2]
23
+
24
+ spec.files = `git ls-files -z`.split("\x0")
25
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
26
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_development_dependency "bundler", "~> 1.7"
30
+ spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "rspec"
32
+ spec.add_development_dependency "guard", "2.12"
33
+ spec.add_development_dependency "guard-rspec"
34
+ spec.add_development_dependency "guard-bundler"
35
+ end
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require 'attach_function'
5
+
6
+ module Math
7
+ module MethodVersions
8
+ extend AttachFunction
9
+ (Math.methods - Object.methods).each do |m|
10
+ puts "Attaching #{m}"
11
+ attach_function m
12
+ end
13
+ end
14
+ end
15
+
16
+ Numeric.include(Math::MethodVersions)
17
+ p "3.14.sin = #{3.14.sin}"
18
+ p "10.log = #{10.log10}"
19
+ p "4.sqrt = #{4.sqrt}"
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ module AttachFunction
4
+ #
5
+ #attach_function defines new methods that are partial applications of a target function where the first argument to the target function gets fixed to self.
6
+ #
7
+ #The name of the newly defined method will be the basename of the target function (the module path gets stripped) or a user-specified name.
8
+ #The receiver of relatively specified parameter functions will be the current module, if a user-specified name is given and
9
+ #the user-specified name is not the same as the basename of the target function, or the enclosing module, if no-user specified name is provided or
10
+ #if the user-specified name is the same as the basename of the parameter.
11
+ #
12
+ #Usage:
13
+ #
14
+ #module MyModule
15
+ # def function_method1(arg1, arg2); end
16
+ # def function_method2(arg1); end
17
+ #
18
+ # module MethodVersions
19
+ # extend Attachmethod
20
+ # attach_function :function_method1
21
+ # attach_function :function_method2
22
+ # end
23
+ #
24
+ #See the specs and the example folder for more examples.
25
+
26
+ def _receiver_and_message(method_name, function_symbol)
27
+ #Parse the function symbol to get the receiver and the function's basename
28
+ if function_symbol.match(/(.*)(?:::|\.)([^:.]*)$/)
29
+ receiver, function_method = $1, $2
30
+ receiver = receiver != "" && eval(receiver) || Object
31
+ else
32
+ #No explicit receiver
33
+ function_method = function_symbol
34
+ #If no receiver is specified, send it to self
35
+ receiver = self
36
+ #Can't send to self if method_name == function_method (or it will recurse and crash):
37
+ # send it to the outer module/class, if there's no outer module, send it to Object
38
+ if (method_name ||= function_method) == function_method
39
+ receiver = self.name
40
+ outer_module = receiver.rpartition('::').first
41
+ receiver = outer_module == "" ? Object : eval(outer_module)
42
+ end
43
+ end
44
+
45
+ return [ receiver, function_method ]
46
+ end
47
+
48
+ def attach_function(method_name = nil, function_symbol)
49
+ receiver, message = _receiver_and_message(method_name, function_symbol)
50
+
51
+ #If no method_name is given, use the basename of the function being attached
52
+ method_name ||= message
53
+
54
+ #The core functionality
55
+ define_method method_name do |*args|
56
+ receiver.send(message, self, *args)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,3 @@
1
+ module AttachFunction
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ module Foo
4
+ def self.add_foo(string)
5
+ string + " foo"
6
+ end
7
+
8
+ #module MethodVersions
9
+ #extend AttachFunction
10
+ #attach_function :add_foo
11
+ #end
12
+ end
13
+ module Three
14
+ def self.add_three(number)
15
+ number + 3
16
+ end
17
+ #module MethodVersions
18
+ #extend AttachFunction
19
+ #attach_function :add_three
20
+ #end
21
+ end
22
+
23
+ module A; end
24
+ module ::A; module B; end; end
25
+
26
+ describe AttachFunction do
27
+ it 'has a version number' do
28
+ expect(AttachFunction::VERSION).not_to be nil
29
+ end
30
+ it "should define an instance method named 'attach_function'" do
31
+ expect(subject.instance_methods(false)).to include(:attach_function)
32
+ end
33
+
34
+ describe "resolving receivers" do
35
+ {
36
+ '::A.m' => [::A, 'm'],
37
+ '::A::m' => [::A, 'm'],
38
+ 'A.m' => [A, 'm'],
39
+ 'A::m' => [A, 'm'],
40
+ '::A::B.m' => [::A::B, 'm'],
41
+ '::A::B::m' => [::A::B, 'm'],
42
+ '::A::B.m' => [::A::B, 'm'],
43
+ '::A::B::m' => [::A::B, 'm'],
44
+ }.each_pair do |k,answers|
45
+ it "should resolve #{k} to #{answers.inspect}" do
46
+ extend AttachFunction
47
+ expect(_receiver_and_message('attach_here',k)).to eq(answers)
48
+ end
49
+ end
50
+
51
+ context "same name and target in the same scope" do
52
+ enclosing_scope = self
53
+ #Don't know how to test this since it creates an unnamed scope
54
+ xit "resolves relatively to the enclosing scope" do
55
+ this_scope = self
56
+ extend AttachFunction
57
+ expect(this_scope).not_to eq(enclosing_scope)
58
+ expect(_receiver_and_message(nil,'m')).to eq([ enclosing_scope, 'm'])
59
+ end
60
+ end
61
+
62
+
63
+ class MyString < String; end
64
+ class MyInt < Integer; end
65
+
66
+ let(:my_string) { MyString.new("my string") }
67
+ let(:my_int) { MyInt.new(7) }
68
+
69
+ it "works with absolute names from a different scope" do
70
+ module AddFooMethod; end
71
+ expect {
72
+ module AddFooMethod
73
+ extend AttachFunction
74
+ attach_function nil,"::Foo::add_foo"
75
+ end
76
+ }.not_to raise_error
77
+ my_string.extend(AddFooMethod)
78
+ expect(my_string).to respond_to(:add_foo)
79
+ expect(my_string.add_foo).to eq("my string foo")
80
+ end
81
+ context "same scope" do
82
+ class TestClass
83
+ def add_bar(obj)
84
+ puts "#{obj} + bar"
85
+ end
86
+ end
87
+ it "works with the same scope as long as we're using a different name" do
88
+ TestClass.extend AttachFunction
89
+ expect(TestClass.new).not_to respond_to(:add_bar_to_self)
90
+ class TestClass
91
+ attach_function :add_bar_to_self, :add_bar
92
+ end
93
+ expect(TestClass.new).to respond_to(:add_bar_to_self)
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ gem_name = File.basename(File.expand_path('../../', __FILE__))
3
+ require gem_name
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attach_function
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Petr Skocik
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: '2.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: '2.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: True in-place file-editing (i.e, inode(input) == inode(output)) like
98
+ with sed, awk, or `ruby i -{p|n}e`, but truly in-place
99
+ email:
100
+ - pskocik@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - ".travis.yml"
108
+ - Gemfile
109
+ - Guardfile
110
+ - README.md
111
+ - Rakefile
112
+ - attach_function.gemspec
113
+ - examples/enclosing_scope.rb
114
+ - lib/attach_function.rb
115
+ - lib/attach_function/version.rb
116
+ - spec/attach_function_spec.rb
117
+ - spec/spec_helper.rb
118
+ homepage: https://github.com/pjump/attach_function.git
119
+ licenses:
120
+ - gplv2
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.2.1
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: True in-place file-editing
142
+ test_files:
143
+ - spec/attach_function_spec.rb
144
+ - spec/spec_helper.rb