stitcher 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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/README.md +107 -0
- data/Rakefile +7 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/docs/matome.md +57 -0
- data/docs/stitcher.md +208 -0
- data/docs/type.md +212 -0
- data/docs/typed.md +15 -0
- data/example/core_ex.rb +23 -0
- data/example/register.rb +33 -0
- data/example/simple.rb +66 -0
- data/example/type.rb +24 -0
- data/lib/stitcher.rb +40 -0
- data/lib/stitcher/accessor.rb +21 -0
- data/lib/stitcher/concepts.rb +6 -0
- data/lib/stitcher/core.rb +31 -0
- data/lib/stitcher/core_ext.rb +7 -0
- data/lib/stitcher/define_method.rb +52 -0
- data/lib/stitcher/operators.rb +37 -0
- data/lib/stitcher/register.rb +31 -0
- data/lib/stitcher/require.rb +27 -0
- data/lib/stitcher/stitch.rb +22 -0
- data/lib/stitcher/type.rb +107 -0
- data/lib/stitcher/type/core_ext.rb +11 -0
- data/lib/stitcher/variadic_argument.rb +12 -0
- data/lib/stitcher/version.rb +3 -0
- data/stitcher.gemspec +25 -0
- metadata +117 -0
data/docs/typed.md
ADDED
data/example/core_ex.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# original source code
|
2
|
+
# http://melborne.github.io/2013/08/30/monkey-patching-for-prudent-rubyists/
|
3
|
+
require "stitcher"
|
4
|
+
|
5
|
+
using Stitcher
|
6
|
+
|
7
|
+
class Array
|
8
|
+
stitcher_require +[Fixnum, Fixnum]
|
9
|
+
def at *indices
|
10
|
+
at(indices.shift).at(*indices)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
p [1,2,3].at(1)
|
15
|
+
# => 1
|
16
|
+
p [[1,2,3], [4,5,6], [7,8,9]].at(1, 2)
|
17
|
+
# => 6
|
18
|
+
p [
|
19
|
+
[[1,2,3],[4,5,6],[7,8,9]],
|
20
|
+
[[10,11,12],[13,14,15],[16,17,18]],
|
21
|
+
[[19,20,21],[22,23,24],[25,26,27]]
|
22
|
+
].at(1, 2, 0)
|
23
|
+
# => 16
|
data/example/register.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require "stitcher"
|
2
|
+
|
3
|
+
class X
|
4
|
+
extend Stitcher::Register
|
5
|
+
|
6
|
+
def initialize value
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
# Register method argument types.
|
10
|
+
stitcher_register :initialize, [Fixnum]
|
11
|
+
|
12
|
+
# Define multi methods.
|
13
|
+
def plus a
|
14
|
+
@value + a
|
15
|
+
end
|
16
|
+
stitcher_register :plus, [Fixnum]
|
17
|
+
|
18
|
+
def plus a
|
19
|
+
@value + a.to_i
|
20
|
+
end
|
21
|
+
stitcher_register :plus, [String]
|
22
|
+
end
|
23
|
+
|
24
|
+
x = X.new 10
|
25
|
+
# x = X.new "10" # Error: No match method.
|
26
|
+
|
27
|
+
# Call X#plus(Fixnum)
|
28
|
+
p x.plus -3
|
29
|
+
# => 7
|
30
|
+
|
31
|
+
# Call X#plus(String)
|
32
|
+
p x.plus "42"
|
33
|
+
# => 57
|
data/example/simple.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require "stitcher"
|
2
|
+
|
3
|
+
# Using stitcher library.
|
4
|
+
using Stitcher
|
5
|
+
|
6
|
+
class Person
|
7
|
+
# Define accessor with variable type(Class).
|
8
|
+
stitcher_accessor name: String, age: Integer
|
9
|
+
|
10
|
+
def set name, age
|
11
|
+
self.name = name
|
12
|
+
self.age = age
|
13
|
+
end
|
14
|
+
# Register set method with Argument types(Classes).
|
15
|
+
stitch :set, [String, Integer]
|
16
|
+
|
17
|
+
# Register for next define method.
|
18
|
+
stitcher_require [Hash]
|
19
|
+
def set hash
|
20
|
+
set hash[:name], hash[:age]
|
21
|
+
end
|
22
|
+
|
23
|
+
# Define "set" method with Argument types.
|
24
|
+
# set(Integer, String)
|
25
|
+
stitcher_define_method(:set, age: Integer, name: String){
|
26
|
+
self.name = name
|
27
|
+
self.age = age
|
28
|
+
}
|
29
|
+
|
30
|
+
# Other define method
|
31
|
+
stitch.set(ary: [String, Integer]){
|
32
|
+
set *ary
|
33
|
+
}
|
34
|
+
|
35
|
+
def print
|
36
|
+
p "name:#{name} age:#{age}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Require format with block object.
|
40
|
+
stitcher_require [String] & Stitcher::Concepts.blockable
|
41
|
+
def print fmt
|
42
|
+
printf(fmt, *yield(name, age))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
x = X.new
|
47
|
+
x.name = "homu"
|
48
|
+
x.age = 14
|
49
|
+
# x.age = 14.0 # Error: No match method.
|
50
|
+
|
51
|
+
x.set "mami", 15
|
52
|
+
x.print
|
53
|
+
# => "name:mami age:15"
|
54
|
+
|
55
|
+
x.set({ name: "saya", age: 14 })
|
56
|
+
x.print
|
57
|
+
# => "name:saya age:14"
|
58
|
+
|
59
|
+
x.set 14, "mado"
|
60
|
+
x.print("%s-%s\n"){ |name, age| [name, age] }
|
61
|
+
# => mado-14
|
62
|
+
|
63
|
+
x.set ["homu", 14]
|
64
|
+
x.print("%s-%s\n"){ |name, age| [age, name] }
|
65
|
+
# => 14-homu
|
66
|
+
|
data/example/type.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "stitcher"
|
2
|
+
using Stitcher::Refinements::Type
|
3
|
+
|
4
|
+
# Object to Type.
|
5
|
+
# Type is Class object.
|
6
|
+
1.type # => Fixnum Type
|
7
|
+
"homu".type # => String Type
|
8
|
+
Numeric.type # => Numeric Type
|
9
|
+
|
10
|
+
|
11
|
+
# Operator is like Class object operators.
|
12
|
+
1.type == Fixnum # => true
|
13
|
+
1.type == Numeric # => false
|
14
|
+
1.type <= Numeric # => true
|
15
|
+
|
16
|
+
|
17
|
+
# Using | operator.
|
18
|
+
# Example: Define Boolean type
|
19
|
+
Boolean = TrueClass | FalseClass
|
20
|
+
|
21
|
+
Boolean == true # => true
|
22
|
+
Boolean == false # => true
|
23
|
+
Boolean == nil # => false
|
24
|
+
Boolean == 0 # => false
|
data/lib/stitcher.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative "./stitcher/version"
|
2
|
+
# require_relative "./stitcher/type"
|
3
|
+
require_relative "./stitcher/define_method"
|
4
|
+
require_relative "./stitcher/accessor"
|
5
|
+
require_relative "./stitcher/stitch"
|
6
|
+
require_relative "./stitcher/operators"
|
7
|
+
require_relative "./stitcher/require"
|
8
|
+
require_relative "./stitcher/variadic_argument"
|
9
|
+
require_relative "./stitcher/core"
|
10
|
+
require_relative "./stitcher/concepts"
|
11
|
+
|
12
|
+
module Stitcher
|
13
|
+
include Accessor
|
14
|
+
include Stitch
|
15
|
+
include Require
|
16
|
+
|
17
|
+
refine Module do
|
18
|
+
include Stitcher
|
19
|
+
end
|
20
|
+
|
21
|
+
refine Class do
|
22
|
+
prepend Operators
|
23
|
+
end
|
24
|
+
|
25
|
+
refine Array do
|
26
|
+
prepend Operators
|
27
|
+
end
|
28
|
+
|
29
|
+
refine Proc do
|
30
|
+
prepend Operators
|
31
|
+
end
|
32
|
+
|
33
|
+
refine Array do
|
34
|
+
include VariadicArgument
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Module
|
39
|
+
include Stitcher::Core
|
40
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative "./register"
|
2
|
+
require_relative "./define_method"
|
3
|
+
|
4
|
+
using Stitcher
|
5
|
+
|
6
|
+
module Stitcher module Accessor
|
7
|
+
include Register
|
8
|
+
|
9
|
+
def stitcher_writer **opt
|
10
|
+
opt.each { |name, type|
|
11
|
+
Register.register(self, "#{name}=", [type], (DefineMethod.as_instance_executable do |var|
|
12
|
+
instance_variable_set "@#{name}", var
|
13
|
+
end))
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def stitcher_accessor **opt
|
18
|
+
attr_reader *opt.keys
|
19
|
+
Accessor.instance_method(:stitcher_writer).bind(self).(opt)
|
20
|
+
end
|
21
|
+
end end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative "./variadic_argument"
|
2
|
+
|
3
|
+
module StitcherArrayEx
|
4
|
+
refine Array do
|
5
|
+
include Stitcher::VariadicArgument
|
6
|
+
end
|
7
|
+
end
|
8
|
+
using StitcherArrayEx
|
9
|
+
|
10
|
+
module Stitcher module Core
|
11
|
+
def stitcher_method_table name
|
12
|
+
instance_eval { @stitcher_method_table ||= {}; @stitcher_method_table[name] ||= {} }
|
13
|
+
end
|
14
|
+
|
15
|
+
def stitcher_method_table_all name
|
16
|
+
mtable = stitcher_method_table(name) unless superclass
|
17
|
+
return stitcher_method_table_all(superclass, name).merge(mtable) if superclass
|
18
|
+
mtable
|
19
|
+
end
|
20
|
+
|
21
|
+
def stitcher_add name, sig, method
|
22
|
+
sig = (method.arity < 0 ? +([Object] * method.arity.abs) : [Object] * method.arity.abs) unless sig
|
23
|
+
stitcher_method_table(name)[sig] = method
|
24
|
+
end
|
25
|
+
|
26
|
+
def stitcher_method_detecting name, *args, &block
|
27
|
+
mtable = stitcher_method_table(name).to_a.reverse
|
28
|
+
_, method = mtable.find {|sig, _| sig.=== args, &block }
|
29
|
+
method
|
30
|
+
end
|
31
|
+
end end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative "./register"
|
2
|
+
require_relative "./accessor"
|
3
|
+
|
4
|
+
|
5
|
+
module Stitcher module DefineMethod
|
6
|
+
include Stitcher::Register
|
7
|
+
|
8
|
+
def self.as_instance_executable &block
|
9
|
+
Object.new.instance_eval do
|
10
|
+
define_singleton_method :stitcher_bind do |obj|
|
11
|
+
proc do |*args, &block_|
|
12
|
+
self_ = obj
|
13
|
+
self_.instance_exec *args, block, &block
|
14
|
+
end
|
15
|
+
end
|
16
|
+
self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def stitcher_define_method name, **opt, &block
|
21
|
+
obj = DefineMethod.as_instance_executable do |*args|
|
22
|
+
_ = args.pop # block object
|
23
|
+
self_ = self
|
24
|
+
obj = Object.new
|
25
|
+
obj.extend(Module.new{
|
26
|
+
private
|
27
|
+
attr_reader *opt.keys
|
28
|
+
})
|
29
|
+
obj.instance_eval do
|
30
|
+
opt.each_with_index { |data, index|
|
31
|
+
name, type = data
|
32
|
+
instance_variable_set "@#{name}", args[index]
|
33
|
+
}
|
34
|
+
|
35
|
+
# define_singleton_method :[] do |name|
|
36
|
+
# self_.instance_eval "@#{ name }"
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# define_singleton_method :[]= do |name, var|
|
40
|
+
# obj.instance_eval { self_.instance_variable_set "@#{name}", var }
|
41
|
+
# end
|
42
|
+
|
43
|
+
define_singleton_method :method_missing do |name, *args, &block|
|
44
|
+
self_.__send__ name, *args, &block
|
45
|
+
end
|
46
|
+
|
47
|
+
instance_eval &block
|
48
|
+
end
|
49
|
+
end
|
50
|
+
Register.register self, name, opt.values, obj
|
51
|
+
end
|
52
|
+
end end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative "./core_ext"
|
2
|
+
|
3
|
+
using StitcherArrayEx
|
4
|
+
|
5
|
+
module Stitcher
|
6
|
+
module Operators
|
7
|
+
def self.require_other other
|
8
|
+
Proc === other || Class === other
|
9
|
+
end
|
10
|
+
|
11
|
+
def & other
|
12
|
+
return super(other) unless Operators.require_other other
|
13
|
+
proc { |it, &block| self.===(it, &block) && other.===(it, &block) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def | other
|
17
|
+
return super(other) unless Operators.require_other other
|
18
|
+
proc { |it, &block| self.===(it, &block) || other.===(it, &block) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def !
|
22
|
+
proc { |it, &block| !(self.===(it, &block)) }
|
23
|
+
end
|
24
|
+
|
25
|
+
refine Class do
|
26
|
+
prepend Operators
|
27
|
+
end
|
28
|
+
|
29
|
+
refine Array do
|
30
|
+
prepend Operators
|
31
|
+
end
|
32
|
+
|
33
|
+
refine Proc do
|
34
|
+
prepend Operators
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative "./core_ext"
|
2
|
+
require_relative "./register"
|
3
|
+
|
4
|
+
using StitcherArrayEx
|
5
|
+
|
6
|
+
|
7
|
+
class UnboundMethod
|
8
|
+
alias_method :stitcher_bind, :bind
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
module Stitcher module Register
|
13
|
+
def self.define_call_method self_, name
|
14
|
+
self_.__send__ :define_method, name do |*args, &block|
|
15
|
+
method = self_.stitcher_method_detecting name, *args, &block
|
16
|
+
|
17
|
+
return super(*args, &block) unless method
|
18
|
+
method = method.stitcher_bind(self) if method.respond_to? :stitcher_bind
|
19
|
+
method.call *args, &block
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.register self_, name, sig = nil, method = self_.instance_method(name)
|
24
|
+
self_.stitcher_add name, sig, method
|
25
|
+
Register.define_call_method self_, name
|
26
|
+
end
|
27
|
+
|
28
|
+
def stitcher_register name, sig, &block
|
29
|
+
Register.register(self, name, sig, block_given? ? block : instance_method(name))
|
30
|
+
end
|
31
|
+
end end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative "./register"
|
2
|
+
# require_relative "../stitcher"
|
3
|
+
|
4
|
+
|
5
|
+
module Stitcher module Require
|
6
|
+
include Register
|
7
|
+
|
8
|
+
def stitcher_require concept
|
9
|
+
@stitcher_require_concept = concept
|
10
|
+
@stitcher_require_methods = instance_methods.map { |name| instance_method name }
|
11
|
+
|
12
|
+
return if methods.include? :method_added
|
13
|
+
def self.method_added name
|
14
|
+
return unless @stitcher_require_concept
|
15
|
+
concept = @stitcher_require_concept
|
16
|
+
@stitcher_require_concept = nil
|
17
|
+
|
18
|
+
method = @stitcher_require_methods.find{ |it| it.name == name }
|
19
|
+
if method && stitcher_method_table(name).empty?
|
20
|
+
# Don't wrap method.
|
21
|
+
stitcher_add name, nil, method
|
22
|
+
end
|
23
|
+
|
24
|
+
Register.register self, name, concept
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative "./register"
|
2
|
+
require_relative "./define_method"
|
3
|
+
|
4
|
+
module Stitcher module Stitch
|
5
|
+
include Register
|
6
|
+
include DefineMethod
|
7
|
+
|
8
|
+
class Definer < BasicObject
|
9
|
+
def initialize obj
|
10
|
+
@obj = obj
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing name, sig, &block
|
14
|
+
DefineMethod.instance_method(:stitcher_define_method).bind(@obj).(name, sig, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def stitch *args, &block
|
19
|
+
return Definer.new self if args.empty?
|
20
|
+
Register.register self, *args, &block
|
21
|
+
end
|
22
|
+
end end
|