uber 0.0.1 → 0.0.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 58b218477b8c36e49f66c8bd47175bf605613ef1
4
+ data.tar.gz: bde8206f4395aa6469f9dfe84eb3651449acd0e3
5
+ SHA512:
6
+ metadata.gz: f08f9af53d76f9800741b6eacd147d031a356b40e309172c1323cf5a80b2f1f70271c1f383f7fbcb2681ac72eaf163b64fc364a36888523688cbbb8147185d22
7
+ data.tar.gz: 8b6a3e28f375e50b829fe60bf5a2a5ab50daafee28cd5e6334d8488e201b85a12ed915ed0e3c1c84938f5006f5ec55a8b1be07141895bdecc8472c24bfa8348e
data/CHANGES.md ADDED
@@ -0,0 +1,3 @@
1
+ # 0.0.2
2
+
3
+ * Add `::inheritable_attr`.
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in uber.gemspec
4
4
  gemspec
5
+
6
+ gem "activesupport"
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Uber
2
2
 
3
- TODO: Write a gem description
3
+ _Gem-authoring tools like class method inheritance in modules, dynamic options and more._
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,22 +8,70 @@ Add this line to your application's Gemfile:
8
8
 
9
9
  gem 'uber'
10
10
 
11
- And then execute:
11
+ Ready?
12
12
 
13
- $ bundle
13
+ # Inheritable Class Attributes
14
14
 
15
- Or install it yourself as:
15
+ This is for you if you want class attributes to be inherited, which is a mandatory mechanism for creating DSLs.
16
16
 
17
- $ gem install uber
17
+ ```ruby
18
+ require 'uber/inheritable_attr'
18
19
 
19
- ## Usage
20
+ class Song
21
+ extend Uber::InheritableAttr
20
22
 
21
- TODO: Write usage instructions here
23
+ inheritable_attr :properties
24
+ self.properties = [:title, :track] # initialize it before using it.
25
+ end
26
+ ```
22
27
 
23
- ## Contributing
28
+ Note that you have to initialize your attribute which whatever you want - usually a hash or an array.
24
29
 
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Added some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
30
+ You can now use that attribute on the class level.
31
+
32
+ ```ruby
33
+ Song.properties #=> [:title, :track]
34
+ ```
35
+
36
+ Inheriting from `Song` will result in the `properties` object being `clone`d to the sub-class.
37
+
38
+ ```ruby
39
+ class Hit < Song
40
+ end
41
+
42
+ Hit.properties #=> [:title, :track]
43
+ ```
44
+
45
+ The cool thing about the inheritance is: you can work on the inherited attribute without any restrictions, as it is a _copy_ of the original.
46
+
47
+ ```ruby
48
+ Hit.properties << :number
49
+
50
+ Hit.properties #=> [:title, :track, :number]
51
+ Song.properties #=> [:title, :track]
52
+ ```
53
+
54
+ It's similar to ActiveSupport's `class_attribute` but with a simpler implementation resulting in a less dangerous potential. Also, there is no restriction about the way you modify the attribute [as found in `class_attribute`](http://apidock.com/rails/v4.0.2/Class/class_attribute).
55
+
56
+ This module is very popular amongst numerous gems like Cells, Representable, Roar and Reform.
57
+
58
+
59
+ # Options
60
+
61
+ Implements the pattern of defining configuration options and evaluating them at run-time.
62
+
63
+ Usually DSL methods accept a number of options that can either be static values, instance method names as symbols, or blocks (lambdas/Procs).
64
+
65
+ Uber::Options.new volume: 9, track: lambda { |s| s.track }
66
+
67
+
68
+ Note that `Options` behaves *and performs* like an ordinary hash when all options are static.
69
+
70
+ only use for declarative assets, not at runtime (use a hash)
71
+
72
+
73
+ # License
74
+
75
+ Copyright (c) 2014 by Nick Sutterer <apotonick@gmail.com>
76
+
77
+ Roar is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -0,0 +1,22 @@
1
+ module Uber
2
+ module InheritableAttr
3
+ def inheritable_attr(name)
4
+ instance_eval %Q{
5
+ def #{name}=(v)
6
+ @#{name} = v
7
+ end
8
+
9
+ def #{name}
10
+ @#{name} ||= InheritableAttribute.inherit_for(self, :#{name})
11
+ end
12
+ }
13
+ end
14
+
15
+ def self.inherit_for(klass, name)
16
+ return unless klass.superclass.respond_to?(name) and value = klass.superclass.send(name)
17
+ value.clone # only do this once.
18
+ end
19
+ end
20
+
21
+ InheritableAttribute = InheritableAttr
22
+ end
@@ -0,0 +1,70 @@
1
+ module Uber
2
+ class Options < Hash
3
+ def initialize(options)
4
+ @static = options
5
+
6
+ options.each do |k,v|
7
+ self[k] = option = Value.new(v)
8
+ @static = nil if option.dynamic?
9
+ end
10
+ end
11
+
12
+ # 1.100000 0.060000 1.160000 ( 1.159762) original
13
+ # 0.120000 0.010000 0.130000 ( 0.135803) return self
14
+ # 0.930000 0.060000 0.990000 ( 0.997095) without v.evaluate
15
+
16
+ # Evaluates every element and returns a hash. Accepts context and arbitrary arguments.
17
+ def evaluate(context, *args)
18
+ return @static unless dynamic?
19
+
20
+ evaluate_for(context, *args)
21
+ end
22
+
23
+ # Evaluates a single value.
24
+ def eval(key, *args)
25
+ self[key].evaluate(*args)
26
+ end
27
+
28
+ private
29
+ def evaluate_for(context, *args)
30
+ {}.tap do |evaluated|
31
+ each do |k,v|
32
+ evaluated[k] = v.evaluate(context, *args)
33
+ end
34
+ end
35
+ end
36
+
37
+ def dynamic?
38
+ not @static
39
+ end
40
+
41
+
42
+ class Value # TODO: rename to Value.
43
+ def initialize(value, options={})
44
+ @value = value || true
45
+ @options = options
46
+ end
47
+
48
+ def evaluate(context, *args)
49
+ return true if @value.is_a?(TrueClass)
50
+
51
+ evaluate_for(context, *args)
52
+ end
53
+
54
+ def dynamic?
55
+ @options[:instance_method] || @value.kind_of?(Proc)
56
+ end
57
+
58
+ private
59
+ def evaluate_for(context, *args)
60
+ return proc!(context, *args) unless @value.kind_of?(Proc)
61
+ @value.call(context, *args) # TODO: change to context.instance_exec and deprecate first argument.
62
+ end
63
+
64
+ def proc!(context, *args)
65
+ return context.send(@value, *args) if @options[:instance_method]
66
+ @value
67
+ end
68
+ end
69
+ end
70
+ end
data/lib/uber/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Uber
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,54 @@
1
+ require 'test_helper'
2
+ require "uber/inheritable_attr"
3
+
4
+ class InheritableAttrTest < MiniTest::Spec
5
+ describe "::inheritable_attr" do
6
+ subject {
7
+ Class.new(Object) do
8
+ extend Uber::InheritableAttribute
9
+ inheritable_attr :drinks
10
+ end
11
+ }
12
+
13
+ it "provides a reader with empty inherited attributes, already" do
14
+ assert_equal nil, subject.drinks
15
+ end
16
+
17
+ it "provides a reader with empty inherited attributes in a derived class" do
18
+ assert_equal nil, Class.new(subject).drinks
19
+ #subject.drinks = true
20
+ #Class.new(subject).drinks # TODO: crashes.
21
+ end
22
+
23
+ it "provides an attribute copy in subclasses" do
24
+ subject.drinks = []
25
+ assert subject.drinks.object_id != Class.new(subject).drinks.object_id
26
+ end
27
+
28
+ it "provides a writer" do
29
+ subject.drinks = [:cabernet]
30
+ assert_equal [:cabernet], subject.drinks
31
+ end
32
+
33
+ it "inherits attributes" do
34
+ subject.drinks = [:cabernet]
35
+
36
+ subklass_a = Class.new(subject)
37
+ subklass_a.drinks << :becks
38
+
39
+ subklass_b = Class.new(subject)
40
+
41
+ assert_equal [:cabernet], subject.drinks
42
+ assert_equal [:cabernet, :becks], subklass_a.drinks
43
+ assert_equal [:cabernet], subklass_b.drinks
44
+ end
45
+
46
+ it "does not inherit attributes if we set explicitely" do
47
+ subject.drinks = [:cabernet]
48
+ subklass = Class.new(subject)
49
+
50
+ subklass.drinks = [:merlot] # we only want merlot explicitely.
51
+ assert_equal [:merlot], subklass.drinks # no :cabernet, here
52
+ end
53
+ end
54
+ end
@@ -1,7 +1,52 @@
1
1
  require 'test_helper'
2
+ require 'uber/inheritable_included'
3
+
4
+ module InheritIncludedTo
5
+ def self.call(includer, proc)
6
+ proc.call(includer) # das will ich eigentlich machen
7
+
8
+ includer.class_eval do
9
+ @block = proc
10
+
11
+ def self.included(base) #
12
+ InheritIncludedTo.call(base, instance_variable_get(:@block))
13
+ end
14
+ end
15
+ end
16
+ end
2
17
 
3
18
  class InheritanceTest < MiniTest::Spec
4
- describe "including" do
5
-
19
+ module Feature
20
+ #extend Uber::InheritedIncluded
21
+
22
+ CODE_BLOCK = lambda { |base| base.class_eval { extend ClassMethods } } # i want that to be executed at every include
23
+
24
+
25
+ def self.included(includer) #
26
+ # CODE_BLOCK.call(base)
27
+ InheritIncludedTo.call(includer, CODE_BLOCK)
28
+ end
29
+
30
+ module ClassMethods
31
+ def feature; end
32
+ end
6
33
  end
34
+
35
+ module Extension
36
+ include Feature
37
+
38
+ # TODO: test overriding ::included
39
+ end
40
+
41
+ module Client
42
+ include Extension
43
+ end
44
+
45
+ module ExtendedClient
46
+ include Client
47
+ end
48
+
49
+ it { Extension.must_respond_to :feature }
50
+ it { Client.must_respond_to :feature }
51
+ it { ExtendedClient.must_respond_to :feature }
7
52
  end
@@ -0,0 +1,72 @@
1
+ require 'test_helper'
2
+ require 'uber/options'
3
+
4
+ class UberOptionTest < MiniTest::Spec
5
+ Value = Uber::Options::Value
6
+
7
+ describe "#dynamic?" do
8
+ it { Value.new(1).dynamic?.must_equal false }
9
+ it { Value.new(true).dynamic?.must_equal false }
10
+ it { Value.new(:loud).dynamic?.must_equal false }
11
+
12
+ it { Value.new(lambda {}).dynamic?.must_equal true }
13
+ it { Value.new(Proc.new{}).dynamic?.must_equal true }
14
+ it { Value.new(:method, :instance_method => true).dynamic?.must_equal true }
15
+ end
16
+
17
+
18
+
19
+ # it "speed" do
20
+ # require "benchmark"
21
+
22
+ # options = 1000000.times.collect do
23
+ # Uber::Options.new(expires: false)
24
+ # end
25
+
26
+ # time = Benchmark.measure do
27
+ # options.each do |opt|
28
+ # opt.evaluate(nil)
29
+ # end
30
+ # end
31
+
32
+ # puts "good results"
33
+ # puts time
34
+ # end
35
+ end
36
+
37
+ class UberOptionsTest < MiniTest::Spec
38
+ Options = Uber::Options
39
+
40
+ let (:dynamic) { Options.new(:volume =>1, :style => "Punkrock", :track => Proc.new { |i| i.to_s }) }
41
+
42
+ describe "#dynamic?" do
43
+ it { Options.new(:volume =>1, :style => "Punkrock").send(:dynamic?).must_equal false }
44
+ it { Options.new(:style => Proc.new{}, :volume =>1).send(:dynamic?).must_equal true }
45
+ end
46
+
47
+ describe "#evaluate" do
48
+
49
+ it { dynamic.evaluate(999).must_equal({:volume =>1, :style => "Punkrock", :track => "999"}) }
50
+
51
+ describe "static" do
52
+ let (:static) { Options.new(:volume =>1, :style => "Punkrock") }
53
+
54
+ it { static.evaluate(nil).must_equal({:volume =>1, :style => "Punkrock"}) }
55
+
56
+ it "doesn't evaluate internally" do
57
+ static.instance_eval do
58
+ def evaluate_for(*)
59
+ raise "i shouldn't be called!"
60
+ end
61
+ end
62
+ static.evaluate(nil).must_equal({:volume =>1, :style => "Punkrock"})
63
+ end
64
+ end
65
+ end
66
+
67
+ describe "#eval" do
68
+ it { dynamic.eval(:volume, 999).must_equal 1 }
69
+ it { dynamic.eval(:style, 999).must_equal "Punkrock" }
70
+ it { dynamic.eval(:track, 999).must_equal "999" }
71
+ end
72
+ end
data/test/test_helper.rb CHANGED
@@ -1,8 +1,5 @@
1
1
  require 'bundler'
2
2
  Bundler.setup
3
3
 
4
- gem 'minitest'
5
- require 'minitest/spec'
6
4
  require 'minitest/autorun'
7
-
8
5
  require 'uber'
data/test/zeugs.rb ADDED
@@ -0,0 +1,54 @@
1
+ module Feature
2
+ module ClassMethods
3
+ def feature
4
+ end
5
+ end
6
+
7
+ # in uber, this would look somehow like
8
+ # module Feature
9
+ # module ClassMethods ... end
10
+
11
+ # extend Uber::InheritableIncluded
12
+ # inheritable_included do |includer|
13
+ # includer.extend ClassMethods
14
+ # end
15
+ # end
16
+
17
+ InheritedIncludedCodeBlock = lambda do |includer|
18
+ includer.extend ClassMethods
19
+ end
20
+
21
+ module RecursiveIncluded
22
+ def included(includer)
23
+ #super # TODO: test me.
24
+ puts "RecursiveIncluded in #{includer}"
25
+
26
+ includer.module_eval do
27
+ InheritedIncludedCodeBlock.call(includer)
28
+ extend RecursiveIncluded
29
+ end
30
+ end
31
+ end
32
+ extend RecursiveIncluded
33
+ end
34
+
35
+ module Client
36
+ include Feature
37
+ end
38
+
39
+ module Extension
40
+ include Client
41
+ end
42
+
43
+ module Plugin
44
+ include Extension
45
+ end
46
+
47
+ module Framework
48
+ include Plugin
49
+ end
50
+
51
+ Client.feature
52
+ Extension.feature
53
+ Plugin.feature
54
+ Framework.feature
data/uber.gemspec CHANGED
@@ -5,7 +5,7 @@ Gem::Specification.new do |gem|
5
5
  gem.authors = ["Nick Sutterer"]
6
6
  gem.email = ["apotonick@gmail.com"]
7
7
  gem.description = %q{A gem-authoring framework.}
8
- gem.summary = %q{Uber is a gem-authoring framework that brings simple module inheritance and more.}
8
+ gem.summary = %q{Gem-authoring tools like class method inheritance in modules, dynamic options and more.}
9
9
  gem.homepage = ""
10
10
 
11
11
  gem.files = `git ls-files`.split($\)
@@ -14,6 +14,7 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "uber"
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Uber::VERSION
17
-
18
- gem.add_development_dependency "minitest", ">= 2.8.1"
17
+
18
+ gem.add_development_dependency "rake", ">= 0.10.1"
19
+ gem.add_development_dependency "minitest", ">= 5.0.0"
19
20
  end
metadata CHANGED
@@ -1,32 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uber
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
5
- prerelease:
4
+ version: 0.0.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Nick Sutterer
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-02-07 00:00:00.000000000 Z
11
+ date: 2014-03-06 00:00:00.000000000 Z
13
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.10.1
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.10.1
14
27
  - !ruby/object:Gem::Dependency
15
28
  name: minitest
16
29
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
30
  requirements:
19
- - - ! '>='
31
+ - - ">="
20
32
  - !ruby/object:Gem::Version
21
- version: 2.8.1
33
+ version: 5.0.0
22
34
  type: :development
23
35
  prerelease: false
24
36
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
37
  requirements:
27
- - - ! '>='
38
+ - - ">="
28
39
  - !ruby/object:Gem::Version
29
- version: 2.8.1
40
+ version: 5.0.0
30
41
  description: A gem-authoring framework.
31
42
  email:
32
43
  - apotonick@gmail.com
@@ -34,41 +45,49 @@ executables: []
34
45
  extensions: []
35
46
  extra_rdoc_files: []
36
47
  files:
37
- - .gitignore
48
+ - ".gitignore"
49
+ - CHANGES.md
38
50
  - Gemfile
39
51
  - LICENSE
40
52
  - README.md
41
53
  - Rakefile
42
54
  - lib/uber.rb
55
+ - lib/uber/inheritable_attr.rb
56
+ - lib/uber/options.rb
43
57
  - lib/uber/version.rb
58
+ - test/inheritable_attr_test.rb
44
59
  - test/inheritance_test.rb
60
+ - test/options_test.rb
45
61
  - test/test_helper.rb
62
+ - test/zeugs.rb
46
63
  - uber.gemspec
47
64
  homepage: ''
48
65
  licenses: []
66
+ metadata: {}
49
67
  post_install_message:
50
68
  rdoc_options: []
51
69
  require_paths:
52
70
  - lib
53
71
  required_ruby_version: !ruby/object:Gem::Requirement
54
- none: false
55
72
  requirements:
56
- - - ! '>='
73
+ - - ">="
57
74
  - !ruby/object:Gem::Version
58
75
  version: '0'
59
76
  required_rubygems_version: !ruby/object:Gem::Requirement
60
- none: false
61
77
  requirements:
62
- - - ! '>='
78
+ - - ">="
63
79
  - !ruby/object:Gem::Version
64
80
  version: '0'
65
81
  requirements: []
66
82
  rubyforge_project:
67
- rubygems_version: 1.8.24
83
+ rubygems_version: 2.2.1
68
84
  signing_key:
69
- specification_version: 3
70
- summary: Uber is a gem-authoring framework that brings simple module inheritance and
71
- more.
85
+ specification_version: 4
86
+ summary: Gem-authoring tools like class method inheritance in modules, dynamic options
87
+ and more.
72
88
  test_files:
89
+ - test/inheritable_attr_test.rb
73
90
  - test/inheritance_test.rb
91
+ - test/options_test.rb
74
92
  - test/test_helper.rb
93
+ - test/zeugs.rb