traitee 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +49 -0
- data/lib/traitee.rb +6 -0
- data/lib/traitee/conflict_solver.rb +42 -0
- data/lib/traitee/dict.rb +34 -0
- data/lib/traitee/merger.rb +16 -0
- data/lib/traitee/trait.rb +45 -0
- data/lib/traitee/version.rb +3 -0
- metadata +66 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b069bf35397a5bd4aebf916dc02feeb4b7b3425b
|
4
|
+
data.tar.gz: 7f3f30df241c16e2cd809db9d042e88477f7a78e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 74f8c42932ad0027f4fe3e698e434d74b358c59cdc742427ac46712f8d8ead8e959d18bd452199ee2ff9ad1edab948423ba8b839f2a23b862f9eed22b3f1daa8
|
7
|
+
data.tar.gz: b6a3e2c8af18e513d38964b14a88597b9914ca887b994f6e4ee3eac2b76e616033bc04feb82f48aecd802caec624c33dc0fcab545874be3d252f4d575fa0a98b
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Traitee
|
2
|
+
|
3
|
+
Mixins or so-called traits for Ruby (like module does not exist :)).
|
4
|
+
|
5
|
+
## How to use Traitee
|
6
|
+
```ruby
|
7
|
+
require 'traitee'
|
8
|
+
|
9
|
+
class Transporter
|
10
|
+
extend(Traitee::Trait)
|
11
|
+
|
12
|
+
serves do
|
13
|
+
def shipping_address
|
14
|
+
'Koniarkova 101, 831 07 Bratislava Slovakia'
|
15
|
+
end
|
16
|
+
|
17
|
+
def current_range
|
18
|
+
kms_left = rand(600) + 10
|
19
|
+
"You have around #{kms_left} kms left."
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Shipper
|
25
|
+
extend(Traitee::Trait)
|
26
|
+
|
27
|
+
attr_accessor :width, :height, :depth
|
28
|
+
|
29
|
+
serves do
|
30
|
+
def set_dimensions(w, h, d)
|
31
|
+
@width = w
|
32
|
+
@height = h
|
33
|
+
@depth = d
|
34
|
+
end
|
35
|
+
|
36
|
+
def dimensions
|
37
|
+
"#{@width} x #{@height} x #{@depth}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Shipment
|
43
|
+
extend Traitee::Merger
|
44
|
+
merge Shipper, Transporter
|
45
|
+
end
|
46
|
+
|
47
|
+
shipment = Shipment.new
|
48
|
+
```
|
49
|
+
For more examples take a look into files inside examples folder.
|
data/lib/traitee.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Traitee
|
2
|
+
class MethodsInConflict < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class ConflictSolver
|
6
|
+
attr_reader :conflicting_methods
|
7
|
+
|
8
|
+
def initialize(methods)
|
9
|
+
@methods = methods
|
10
|
+
@conflicting_methods = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# java reference :P, actual resolved module holder
|
14
|
+
def this
|
15
|
+
@this ||= Module.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def conflictless_method_map
|
19
|
+
@methods.reduce({}) do |res, map|
|
20
|
+
res.merge!(map) { |method_name, method_a, method_b| solve_possible_conflict(method_name, method_a, method_b) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# let it build, actual error will be raised later on all the usages of the method
|
25
|
+
def solve_possible_conflict(method_name, method_a, method_b)
|
26
|
+
method_a == method_b ? method_a : method_in_conflict(method_name, method_a, method_b)
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_in_conflict(method_name, method_a, method_b)
|
30
|
+
conflict_solver = self
|
31
|
+
@conflicting_methods[method_name] = [method_a, method_b]
|
32
|
+
|
33
|
+
# define a method which raises an error - uncallable
|
34
|
+
this.send(:define_method, method_name) do
|
35
|
+
_method_a, _method_b = conflict_solver.conflicting_methods[method_name]
|
36
|
+
fail MethodsInConflict.new "Modules are in conflict with method :#{method_name}"
|
37
|
+
end
|
38
|
+
|
39
|
+
this.instance_method(method_name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/traitee/dict.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Traitee
|
4
|
+
class Dict
|
5
|
+
def initialize
|
6
|
+
@methods = Set.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def <<(method)
|
10
|
+
@methods << method
|
11
|
+
end
|
12
|
+
|
13
|
+
def methods_hash(options = {})
|
14
|
+
except = Array(options[:except])
|
15
|
+
aliases = options.fetch :aliases, {}
|
16
|
+
|
17
|
+
methods_hash = Hash[
|
18
|
+
@methods.map { |method| traitee_module, name = method; [name, traitee_module.instance_method(name)] }
|
19
|
+
]
|
20
|
+
methods_hash = exclusions(methods_hash, except)
|
21
|
+
aliases(methods_hash, aliases)
|
22
|
+
end
|
23
|
+
|
24
|
+
# fetch only methods on included in except opts
|
25
|
+
def exclusions(methods, exclusions)
|
26
|
+
methods.select { |method_name, _| !exclusions.include?(method_name) }
|
27
|
+
end
|
28
|
+
|
29
|
+
# create aliases for selected methods as described in opts
|
30
|
+
def aliases(methods, aliases)
|
31
|
+
Hash[methods.map { |method_name, _method| [(aliases.include?(method_name) ? aliases[method_name] : method_name), _method] }]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'traitee/conflict_solver'
|
2
|
+
|
3
|
+
module Traitee
|
4
|
+
module Merger
|
5
|
+
|
6
|
+
#just check for conflicts, if there are any, we will raise an Error on call. Dont overwrite owners methods
|
7
|
+
def merge(*maps)
|
8
|
+
maps.map! { |map| Hash === map ? map : map.methods }
|
9
|
+
conflictless_map = ConflictSolver.new(maps).conflictless_method_map
|
10
|
+
conflictless_map.each do |method_name, method|
|
11
|
+
# do not run check for included super methods
|
12
|
+
send(:define_method, method_name, method) unless instance_methods(false).include?(method_name)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'traitee/merger'
|
3
|
+
require 'traitee/dict'
|
4
|
+
|
5
|
+
module Traitee
|
6
|
+
module Trait
|
7
|
+
extend Forwardable # we want some delegators in here, to delegate to the included trait
|
8
|
+
def_instance_delegators :this, :instance_methods, :send
|
9
|
+
alias_method :[], :methods
|
10
|
+
|
11
|
+
include Merger
|
12
|
+
|
13
|
+
def this
|
14
|
+
@this ||= Module.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def dict
|
18
|
+
@dict ||= Dict.new
|
19
|
+
end
|
20
|
+
|
21
|
+
# usable methods
|
22
|
+
def methods(options = {})
|
23
|
+
served_from(this, *this.instance_methods)
|
24
|
+
dict.methods_hash(options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# helper for actual method definitions
|
28
|
+
def serves(&method_def)
|
29
|
+
this.module_eval(&method_def)
|
30
|
+
end
|
31
|
+
|
32
|
+
# store Module where method is defined (trait) and actual method name
|
33
|
+
def served_from(trait_module, *methods)
|
34
|
+
methods.each { |method_name| dict << [trait_module, method_name] }
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.subject_composition(*params, &block)
|
38
|
+
Class.new do
|
39
|
+
extend Trait
|
40
|
+
merge(*params) unless params.empty?
|
41
|
+
serves(&block) if block
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: traitee
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Lieskovsky
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-11-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Traits for Ruby - more dynamic implementation of classic include/extend
|
28
|
+
feature.
|
29
|
+
email:
|
30
|
+
- adamliesko@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- README.md
|
36
|
+
- lib/traitee.rb
|
37
|
+
- lib/traitee/conflict_solver.rb
|
38
|
+
- lib/traitee/dict.rb
|
39
|
+
- lib/traitee/merger.rb
|
40
|
+
- lib/traitee/trait.rb
|
41
|
+
- lib/traitee/version.rb
|
42
|
+
homepage: http://github.com/adamliesko/traitee
|
43
|
+
licenses:
|
44
|
+
- MIT
|
45
|
+
metadata: {}
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 2.4.5.1
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: Mixins or so called traits for Ruby
|
66
|
+
test_files: []
|