jinterface 0.0.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.
@@ -0,0 +1,38 @@
1
+ module JInterface
2
+ class ArgRange
3
+ attr :min, :max
4
+ def initialize(meth)
5
+ reset(meth)
6
+ end
7
+ def +(range)
8
+ if range.is_a? self.class
9
+ @min = range.min if range.min < @min
10
+ @max = range.max if range.max > @max
11
+ end
12
+ return self
13
+ end
14
+ def cover?(range)
15
+ return range.is_a?(self.class) &&
16
+ @min <= range.min && @max >= range.max
17
+ end
18
+ def reset(meth)
19
+ @min, @max = getMethodRange(meth)
20
+ end
21
+ def to_s()
22
+ "(#{@min}, #{@max}#{@max == Float::INFINITY ? ']' : ')'}"
23
+ end
24
+ private
25
+ def getMethodRange(meth)
26
+ return 0, 0 unless meth.is_a?(UnboundMethod) or meth.is_a?(Method)
27
+ #Get min and max number of args for method
28
+ min = 0
29
+ params = meth.parameters
30
+ max = params.length
31
+ params.each do |type, |
32
+ ++min if type == :req
33
+ max = Float::INFINITY if type == :rest
34
+ end
35
+ return min, max
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,111 @@
1
+ require 'jinterface/interface_class_methods'
2
+ require 'jinterface/arg_range.rb'
3
+ module JInterface
4
+ module InterfaceClassMethods
5
+ def include(*args)
6
+ #For each inclusion
7
+ args.each do |mod|
8
+ #Make sure it is an interface
9
+ raise TypeError.new(
10
+ "Cannot include non-interface module"\
11
+ " '#{mod.name}' in interface '#{self.name}'."
12
+ ) unless JInterface.interface? mod
13
+ #Add the method arrays together
14
+ arg_ranges = mod.instance_variable_get(:@arg_ranges)
15
+ arg_ranges.each do |method_name, range|
16
+ @arg_ranges[method_name] = range + @arg_ranges[method_name]
17
+ end
18
+ #Include it
19
+ super mod
20
+ end
21
+ end
22
+ def included(obj)
23
+ #Ignore if included in an interface,
24
+ #include method will take care of checks
25
+ return if JInterface.interface?(obj)
26
+ #Cache public obj method names
27
+ obj_methods = Hash[obj.public_instance_methods.map.with_index.to_a]
28
+ #Check interface methods are implemented in obj
29
+ act_range = JInterface::ArgRange.new(nil)
30
+ self.public_instance_methods.each do |method_name|
31
+ #If method does not exist
32
+ if not obj_methods.key? method_name
33
+ #Raise error if under a different scope
34
+ [:private, :protected].each do |scope|
35
+ raise NameError.new(
36
+ "Method '#{method_name}' in class '#{obj.name}'"\
37
+ " must be declared as public, not #{scope},"\
38
+ " as declared in interface '#{self.name}'."
39
+ ) if obj.send("#{scope}_method_defined?", method_name)
40
+ end
41
+ #If here, method does not exist. This is possible
42
+ #if the method was removed or made undefined
43
+ raise NotImplementedError.new(
44
+ "Method '#{method_name}' must be implemented in class"\
45
+ " '#{obj.name}' as declared in interface '#{self.name}'."
46
+ )
47
+ end
48
+ #Make sure method was overriden (implemented)
49
+ meth = obj.public_instance_method method_name
50
+ raise NotImplementedError.new(
51
+ "Method '#{method_name}' must be implemented in class"\
52
+ " '#{obj.name}' as declared in interface '#{meth.owner.name}'."
53
+ ) if JInterface.interface? meth.owner
54
+ #Make sure method can handle number of args defined
55
+ act_range.reset(meth)
56
+ exp_range = @arg_ranges[method_name]
57
+ raise ArgumentError.new(
58
+ "Method '#{method_name}' in class '#{obj.name}'"\
59
+ " must handle #{exp_range} arguments, not #{act_range},"\
60
+ " as declared in included interface(s)."
61
+ ) unless act_range.cover? exp_range
62
+ end
63
+ end
64
+ def method_added(method_name)
65
+ meth = self.public_instance_method(method_name)
66
+ @arg_ranges[method_name] = JInterface::ArgRange.new(meth) + @arg_ranges[method_name]
67
+ end
68
+ def private(*args)
69
+ raise SyntaxError.new(
70
+ "Interface '#{self.name}' cannot declare"\
71
+ " private methods, only public methods."
72
+ )
73
+ end
74
+ def protected(*args)
75
+ raise SyntaxError.new(
76
+ "Interface '#{self.name}' cannot declare"\
77
+ " protected methods, only public methods."
78
+ )
79
+ end
80
+ def singleton_method_added(*args)
81
+ raise SyntaxError.new(
82
+ "Interface '#{self.name}' cannot declare"\
83
+ " class methods, only instance methods."
84
+ )
85
+ end
86
+ def extend(*args)
87
+ raise SyntaxError.new(
88
+ "Interface '#{self.name}' cannot extend,"\
89
+ " only include other interfaces."
90
+ )
91
+ end
92
+ def extended(obj)
93
+ raise SyntaxError.new(
94
+ "Interface '#{self.name}' cannot be "\
95
+ " extended, only included, in '#{obj.name}'."
96
+ )
97
+ end
98
+ def prepend(*args)
99
+ raise SyntaxError.new(
100
+ "Interface '#{self.name}' cannot prepend,"\
101
+ " only include other interfaces."
102
+ )
103
+ end
104
+ def prepended(obj)
105
+ raise SyntaxError.new(
106
+ "Interface '#{self.name}' cannot be "\
107
+ " prepended, only included, in '#{obj.name}'."
108
+ )
109
+ end
110
+ end
111
+ end
data/lib/jinterface.rb ADDED
@@ -0,0 +1,82 @@
1
+ require 'jinterface/interface_class_methods'
2
+ module JInterface
3
+ class << self
4
+ def included(mod)
5
+ #Do not do anything if in production
6
+ return if production?
7
+ #Make sure JInterface used with module
8
+ raise TypeError.new(
9
+ "JInterface cannot be used with class"\
10
+ " '#{mod.name}', only with modules."
11
+ ) if mod.instance_of? Class
12
+ #Extend module
13
+ mod.class_eval do
14
+ extend JInterface::InterfaceClassMethods
15
+ @arg_ranges = {
16
+ #method_name => ArgRange
17
+ }
18
+ #In case JInterface inclusion was
19
+ #not first thing in class declaration:
20
+ #Raise error if private method defined
21
+ private_instance_methods.each do |method_name|
22
+ private method_name
23
+ end
24
+ #Raise error if protected method defined
25
+ protected_instance_methods.each do |method_name|
26
+ protected method_name
27
+ end
28
+ #Raise error if class method defined
29
+ methods(false).each do |method_name|
30
+ singleton_method_added method_name
31
+ end
32
+ #Raise error if non-interface included
33
+ included_modules.each do |mod|
34
+ include mod unless JInterface.interface? mod
35
+ end
36
+ #Raise error if module prepended
37
+ prepended_modules.each do |mod|
38
+ prepend mod
39
+ end if defined? prepended_modules
40
+ #Raise error if module extended
41
+ (
42
+ (class << mod; self; end).included_modules -
43
+ Module.included_modules -
44
+ [JInterface::InterfaceClassMethods]
45
+ ).each do |mod|
46
+ extend mod
47
+ end
48
+ #Send each method through method_added method
49
+ public_instance_methods(false).each do |method_name|
50
+ method_added(method_name)
51
+ end
52
+ end
53
+ end
54
+ def extended(obj)
55
+ raise SyntaxError.new(
56
+ "Interface '#{self.name}' cannot be "\
57
+ " extended, only included, in '#{obj.name}'."
58
+ )
59
+ end
60
+ def prepended(obj)
61
+ raise SyntaxError.new(
62
+ "Interface '#{self.name}' cannot be "\
63
+ " prepended, only included, in '#{obj.name}'."
64
+ )
65
+ end
66
+ def interface?(obj)
67
+ ( obj == JInterface or
68
+ ( obj.instance_of?(Module) and
69
+ (class << obj; self end) < JInterface::InterfaceClassMethods
70
+ )
71
+ ) ? true : false
72
+ end
73
+ def production=(flag)
74
+ @enabled = flag == true
75
+ end
76
+ def production?()
77
+ return @enabled ||= false
78
+ end
79
+ end
80
+ end
81
+ #Turn JInterface checking on or off
82
+ JInterface.production = defined?(Rails) and Rails.is_a?(Class) ? Rails.env.production? : false
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jinterface
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 0
10
+ version: 0.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Michael Rojas
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain:
17
+ - |
18
+ -----BEGIN CERTIFICATE-----
19
+ MIIDRDCCAiygAwIBAgIBADANBgkqhkiG9w0BAQUFADBIMRowGAYDVQQDDBFkZXYu
20
+ bWljaGFlbC5yb2phczEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPy
21
+ LGQBGRYDY29tMB4XDTE0MDQxMTIyMzM1M1oXDTE1MDQxMTIyMzM1M1owSDEaMBgG
22
+ A1UEAwwRZGV2Lm1pY2hhZWwucm9qYXMxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDET
23
+ MBEGCgmSJomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
24
+ ggEBAKqba7uCWi7wkNCeUFLDa+Ql5fG75E8kGruxP5BBAWhOUwjWpKfUv/8Paqlk
25
+ 7P3rtNMLnofentNQciXLgSlK0jwyO9Kuevi3nIPbFuVcQR5D58z9SLezYQSl1hPu
26
+ RaO2IFLfnakj2QjyH3RVdzBDq3+merqkI0qmDvWCs6aJljHsAOBjk5DftY5elCDP
27
+ ooks39ZVpsdwpoAewmtq9uvMivCRz+Vf1yJYVoRuVUSczoOPgN4PW/MJfLQhih5b
28
+ FrsDqGQdNgSjgL7rTZMd0/tiUdo9GaGYG/Rl3TtzlyxB9pJTTc1rDmi/1A2G6Weo
29
+ UX97pHPgP+0WEl3e41jbYkClSfMCAwEAAaM5MDcwHQYDVR0OBBYEFDWsnI/cwObC
30
+ XU3Yf8T0vyKp9Wb+MAsGA1UdDwQEAwIEsDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEB
31
+ BQUAA4IBAQAcCK9Sfoae8T+Sw7xY5ZMUAt55IO8Ldq61J+V8+Q49vgXb7/m379DC
32
+ FZhia4pj4n1g//M0nHm2/yQblXK7qwkYpGB3uEK5yedaY5fCGZlRe67rcPJ4No1x
33
+ tHpBaYknGBP3ITEt1Btw5HhPpccirBk8cBIP9vEN/k9yNn9jpVRRBLXiXaKusDRy
34
+ NccuJexQuG86gK8tnQh1kN2t+MA5UkDeHWsysJrEsT1/p6UChw60MhlQ2gFTrIvu
35
+ EBm0ICzl7th3TQgzeiWbMUiUx7k5B+Oi/btCNjCIGkpWyWC+nL1SweWtOFGQGuGm
36
+ UX363H4LFf3sXXUY2b+Nf5+zMlVQADoL
37
+ -----END CERTIFICATE-----
38
+
39
+ date: 2014-04-09 00:00:00 Z
40
+ dependencies: []
41
+
42
+ description: Simulate java interfaces in ruby to enforce public class implementation
43
+ email: dev.michael.rojas@gmail.com
44
+ executables: []
45
+
46
+ extensions: []
47
+
48
+ extra_rdoc_files: []
49
+
50
+ files:
51
+ - lib/jinterface.rb
52
+ - lib/jinterface/arg_range.rb
53
+ - lib/jinterface/interface_class_methods.rb
54
+ homepage: https://github.com/havelessbemore/JInterface
55
+ licenses:
56
+ - MIT
57
+ post_install_message:
58
+ rdoc_options: []
59
+
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.8.24
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: JInterface
87
+ test_files: []
88
+
metadata.gz.sig ADDED
Binary file