abject 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: 45d9afce900946a9a96389992c671a471e2d001e
4
+ data.tar.gz: 74e47d669de75444423662f5deecfe29ae67d640
5
+ SHA512:
6
+ metadata.gz: d35980cf8344592e5a8e12799c4db4449cf5e29c997566f698fe0a7ae2b39959661cdccafbd755f0c544b3f6b7616ea4f14e0ec2c7a63673f251112b3e2d4f76
7
+ data.tar.gz: 73b59179bd0882ce83c436640b5825520c4a7b24294de25f54a0d103dc0a7c81009a859dc09a5a8b6ee9cf30eac4fcef4f95c2e438ef4d322a484f18d75b1183
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /specs/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in abject.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Dave Kinkead
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,179 @@
1
+ # Abject
2
+
3
+ ### Because you're been doing all it wrong!
4
+
5
+ Abject Orientated Programming (Abject-O) is a set of best practices developed by [Greg Jorgensen](http://typicalprogrammer.com/abject-oriented/) that promotes code reuse and ensures programmers are producing code that can be used in production for a long time.
6
+
7
+ For too long, the beauty of ruby has been sullied by the misguided follies of Gamma & his cronies. Abject rectifies this by finally bringing Abject-O to Ruby is a snapply DSL.
8
+
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+
15
+ gem 'abject'
16
+
17
+
18
+ And then execute:
19
+
20
+
21
+ $ bundle
22
+
23
+
24
+ Or install it yourself as:
25
+
26
+
27
+ $ gem install abject
28
+
29
+
30
+ ## Key Concepts
31
+
32
+ ### Inheritance
33
+
34
+ Inheritance is a way to retain features of old code in newer code. The programmer derives from an existing function or block of code by making a copy of the code, then making changes to the copy. The derived code is often specialized by adding features not implemented in the original. In this way the old code is retained but the new code inherits from it.
35
+
36
+ Unlike Object Oriented programming, inheritance in Abject-O need not be limited to classes - functions and blocks may also inherit from other code. Programs that use inheritance are characterized by similar blocks of code with small differences appearing throughout the source. Another sign of inheritance is static members: variables and code that are not directly referenced or used, but serve to maintain a link to the original base or parent code.
37
+
38
+
39
+ class Customer
40
+
41
+ def find_name(id)
42
+ results = DB.query :customer, id
43
+ fullname = "#{results[1]} #{results[2]}"
44
+ end
45
+
46
+
47
+ def find_email(id)
48
+ results = DB.query :customer, id
49
+ fullname = "#{results[1]} #{results[2]}"
50
+
51
+ # email addresses can now be found in the
52
+ # `fax-home` column
53
+ email = "#{results[5]}"
54
+ end
55
+
56
+ end
57
+
58
+
59
+ The function `find_email` was inherited from `find_name` when email addresses were added to the application. Inheriting code in this way leverages working code with less risk of introducing bugs. But this is Ruby - implicit is better than explicit - so Abject provides a helpful DSL for functional and block inheritance that dynamically copies and pastes the inherited code at run time. [View source](lib/abject/inheritance.rb).
60
+
61
+
62
+ class Customer
63
+ include Abject::Inheritance
64
+
65
+ def find_name(id)
66
+ results = DB.query :customer, id
67
+ fullname = "#{results[1]} #{results[2]}"
68
+ end
69
+
70
+ def find_email(id)
71
+ inherits_from :find_name, id: id do
72
+ email = "#{results[5]}"
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+
79
+ ### Polymorphism
80
+
81
+ Code is polymorphic when it gives different outputs for different kinds of inputs. To quote wikipedia, a function is polymorphic if it:
82
+
83
+ > denotes different and potentially heterogeneous implementations depending on a limited range of individually specified types and combinations
84
+
85
+ When learning Abject-O techniques, programmers frequently get caught up by this idea. It sounds hard but polymorphism is actually simple and easy to implement. As an example, the functions above can be rewritten as a single polymorphic function by inheriting the code that already works and then encapsulating it into a new function:
86
+
87
+
88
+ class Customer
89
+
90
+ def find_customer(attrib, id)
91
+ if attrib == 'name'
92
+ results = DB.query :customer, id
93
+ fullname = "#{results[1]} #{results[2]}"
94
+ elsif attrib == 'email'
95
+ results = DB.query :customer, id
96
+ fullname = "#{results[1]} #{results[2]}"
97
+
98
+ # email addresses can now be found in the
99
+ # `fax-home` column
100
+ email = "#{results[5]}"
101
+ end
102
+
103
+ end
104
+
105
+
106
+ ### Encapsulation
107
+
108
+ The idea behind encapsulation is to keep the data separate from the code. This is sometimes called data hiding, but the data is not really hidden, just protected inside another layer of code. For example, it’s not a good practice to scatter database lookups all over the place. An Abject-O practice is to wrap or hide the database in a function, thereby encapsulating the database. In the `find_name` function above the database is not queried directly — a function is called to read the database record. All `find_name` and `find_email` (and the many other functions like them) “know” is where in the customer record to find the bits of data they need. How the customer record is read is encapsulated in some other module.
109
+
110
+ Encapsulation can also be achieved through the use of protected functions. The importance of function safety cannot be stressed enough as unprotected methods may result in data spillage, tight object coupling, and other morally questionable behaviours. In Ruby, functions can be protected with the `#` character and many IDE's also provide macros to protect large sections of your code base efficiently - `opt arrow` on Sublime Text for example.
111
+
112
+
113
+ # An exposed public method
114
+ def exposed_method(customer, id)
115
+ query = DB.find :customer, id
116
+ customer = Customer.new query
117
+ end
118
+
119
+ # A protected method
120
+ # def protected_method(customer, id)
121
+ # query = DB.find :customer, id
122
+ # customer = Customer.new query
123
+ # end
124
+
125
+
126
+ The Abject gem provides an elegant means of protecting methods from any unwanted spillage and leakage that might result from tight coupling. Simply declare a function protected at the end of a class and let Ruby's metaprogramming magic do its work. [View source](lib/abject/encapsulation.rb).
127
+
128
+
129
+ class Foo
130
+ include Abject::Encapsulation
131
+
132
+ def bar
133
+ "bar"
134
+ end
135
+
136
+ def baz
137
+ "baz"
138
+ end
139
+
140
+ protects :baz
141
+
142
+ end
143
+
144
+ p Foo.new.bar # => "bar"
145
+ p Foo.new.baz # => nil
146
+
147
+
148
+ ### DRY
149
+
150
+ Don’t Repeat Yourself (DRY) is a principle of software development, aimed at reducing repetition of information of all kinds, especially useful in multi-tier architectures. The DRY principle is stated as
151
+
152
+ > Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
153
+
154
+ The antonym of DRY is, obviously, WET: Write Everything Twice. When the DRY principle is applied successfully, a modification of any single element of a system does not require a change in other logically unrelated elements.
155
+
156
+ Owing to their naivety and laziness, junior developers often try to implement the DRY paradigm by copying and pasting code they found somewhere on the internet. This is of course, myopic and inefficient. The Abject-O Rubyist doesn't need to debased themselves with such short sighted behaviour though, as the Abject gem turns the entire internet into your code base. [View source](lib/abject/dry.rb)
157
+
158
+
159
+ class FizzBuzzer
160
+ include Abject::DRY
161
+
162
+ def fizzbuzz(number)
163
+ url = 'http://stackoverflow.com/questions/24435547/ruby-fizzbuzz-not-working-as-expected#24435693'
164
+ adjustments = {'puts' => 'return', 'def fizzbuzz(n)' => 'lambda do |n|'}
165
+ fuck_it_just_copy_something_from_stackoverflow(url, adjustments).call(number).last.to_s
166
+ end
167
+
168
+ end
169
+
170
+
171
+ ---
172
+
173
+
174
+ ## Contributing
175
+
176
+ 1. Download the zipped binary https://github.com/davekinkead/abject/archive/master.zip
177
+ 2. Run your [unit test]
178
+ 3. Zip your new code and appropriately name the file abject-v-0.0.1-john-smith-2014-11-20-fixed-typos.zip
179
+ 4. FTP to the SourceForge project page
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake"
3
+
4
+ task default: [:specs]
5
+
6
+ task :specs do
7
+ $LOAD_PATH.unshift 'lib', 'specs'
8
+ Dir.glob('specs/*_spec*.rb').each { |file| require_relative file }
9
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'abject/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "abject"
8
+ spec.version = Abject::VERSION
9
+ spec.authors = ["Dave Kinkead"]
10
+ spec.email = ["dave@kinkead.com.au"]
11
+ spec.summary = %q{Abject Oriented Programming for the Rubyist}
12
+ spec.description = %q{Abject provides a snappy DSL to make Abject-O a reality!}
13
+ spec.homepage = "https://github.com/davekinkead/abject"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "curb"
22
+ spec.add_dependency "nokogiri"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.7"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ end
@@ -0,0 +1,4 @@
1
+ require 'abject/version'
2
+ require 'abject/inheritance'
3
+ require 'abject/encapsulation'
4
+ require 'abject/dry'
@@ -0,0 +1,26 @@
1
+ require 'curb'
2
+ require 'nokogiri'
3
+
4
+ module Abject
5
+ module DRY
6
+
7
+ # Why copy & paste answers from stack overflow when you can curl & eval them!
8
+ # Expects a url#answer-id and a hash of adjustments to the answer code to gsub over
9
+ def fuck_it_just_copy_something_from_stackoverflow(url, adjustments)
10
+ # build the adjustment lambda
11
+ edit = "lambda { |method_string| method_string"
12
+ adjustments.each { |k,v| edit += ".gsub('#{k}', '#{v}')" }
13
+ edit += "}"
14
+
15
+ # then get some of that overflow goodness
16
+ answer = url.split('#').last
17
+ @doc ||= Nokogiri::HTML Curl.get(url).body_str
18
+ @doc.css("#answer-#{answer} code").each do |code|
19
+ # Oh yeah, it's lambda time! Eval the edit string, pass it the overflow code
20
+ # and eval the resulting lambda
21
+ return eval eval(edit).call code.content
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ require 'abject/reader'
2
+
3
+ module Abject
4
+
5
+ # The idea behind encapsulation is to keep the data separate from the code. This is sometimes
6
+ # called data hiding, but the data is not really hidden, just protected inside another layer
7
+ # of code. For example, it’s not a good practice to scatter database lookups all over the place.
8
+ # An abject practice is to wrap or hide the database in functions or subroutines, thereby
9
+ # encapsulating the database. In the `find_name` function above the database is not queried
10
+ # directly — a function is called to read the database record. All `find_name` and `find_email`
11
+ # (and the many other functions like them) “know” is where in the customer record to find
12
+ # the bits of data they need. How the customer record is read is encapsulated in some other module.
13
+
14
+ # Encapsulation can also be achieved through the use of protected functions. The importance
15
+ # of function safety cannot be stressed enough. Unprotected methods result in data spillage,
16
+ # tight object coupling, and other morally questionable behaviours. Abject-O achieves this
17
+ # with the `#` character and many IDE's also provide macros to protect large sections of
18
+ # your code base efficiently - `opt arrow` on Sublime Text for example.
19
+ module Encapsulation
20
+ include Abject::Reader
21
+
22
+ def self.included(base)
23
+ base.extend ClassMethods
24
+ end
25
+
26
+ module ClassMethods
27
+
28
+ # Copying and pasting is so 1999. Lets use some ruby meta programming magic to
29
+ # dyanmically protect our methods with some `#` hashes at run time!
30
+ def protects(name)
31
+ location = self.instance_method(name).source_location
32
+ define_method name do |*args|
33
+ eval parse_method(location).gsub(/^/m, "#")
34
+ end
35
+
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,26 @@
1
+ require 'abject/reader'
2
+
3
+ module Abject
4
+
5
+ # Inheritance is a way to retain features of old code in newer code. The programmer derives
6
+ # from an existing function or block of code by making a copy of the code, then making
7
+ # changes to the copy. The derived code is often specialized by adding features not
8
+ # implemented in the original. In this way the old code is retained but the new code inherits
9
+ # from it.
10
+
11
+ # Unlike Object Oriented programming, inheritance in Abject-O need not be limited to classes
12
+ # - functions and blocks may also inherit from other code. Programs that use inheritance are
13
+ # characterized by similar blocks of code with small differences appearing throughout the source.
14
+ # Another sign of inheritance is static members: variables and code that are not directly
15
+ # referenced or used, but serve to maintain a link to the original base or parent code.
16
+ module Inheritance
17
+ include Abject::Reader
18
+
19
+ # Method chaining helps methods adhere to the single responsibility principle as well as
20
+ # improving performance and saving memory by getting rid of all those pesky local variables.
21
+ # Such eval! So performant! Much wow!
22
+ def inherits_from(parent, *args, &block)
23
+ eval("Proc.new { |#{args.first.keys.map { |k| k.to_s }.join ','}| #{parse_method method(parent).to_proc.source_location}\n#{parse_method block.source_location} }").call args
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ module Abject
2
+ module Reader
3
+
4
+ private
5
+
6
+ # Save time copy & pasting old methods by doing it at run time!
7
+ # TODO: count block keywords for loops and conditionals
8
+ def parse_method(location)
9
+ File.readlines(location[0])[location[1].to_i..-1].join.split("end\n").first
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Abject
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: abject
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dave Kinkead
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: curb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ description: Abject provides a snappy DSL to make Abject-O a reality!
70
+ email:
71
+ - dave@kinkead.com.au
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - abject.gemspec
82
+ - lib/abject.rb
83
+ - lib/abject/dry.rb
84
+ - lib/abject/encapsulation.rb
85
+ - lib/abject/inheritance.rb
86
+ - lib/abject/reader.rb
87
+ - lib/abject/version.rb
88
+ - vendor/cache/curb-0.8.6.gem
89
+ - vendor/cache/mini_portile-0.6.1.gem
90
+ - vendor/cache/nokogiri-1.6.4.1.gem
91
+ - vendor/cache/rake-10.3.2.gem
92
+ homepage: https://github.com/davekinkead/abject
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.2.2
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: Abject Oriented Programming for the Rubyist
116
+ test_files: []