traitee 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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.
@@ -0,0 +1,6 @@
1
+ require 'traitee/merger'
2
+ require 'traitee/trait'
3
+ require 'traitee/version'
4
+
5
+ module Traitee
6
+ end
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Traitee
2
+ VERSION = '0.0.1'
3
+ 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: []