traitee 0.0.1

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.
@@ -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: []