sire 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 30413fa266e06f4f15e3880b75de8ecf4f290948
4
+ data.tar.gz: 8411be1b81784b065a1175ed80b1ad6f49794253
5
+ SHA512:
6
+ metadata.gz: 5e73d3110599e928b4ef46f91dbb9d3132d51d4ce2552d921eeb719607421b373b0c3d01afefa39b40275f54f8cab965eac1c38104d0367ccb7b714dedcbceb2
7
+ data.tar.gz: 1d4696476497073ec0989891d730b1c7c557427dc0ce24cdba2d62a407c9c5d9110be91058e58fdf74617f42dcc8d84eb60cb83ddd9c6633f34fce32b5c3ec52
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Max White
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.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # Sire
2
+
3
+ [![Build Status](https://travis-ci.org/mushishi78/sire.svg?branch=master)](https://travis-ci.org/mushishi78/sire)
4
+ [![Gem Version](https://badge.fury.io/rb/sire.svg)](http://badge.fury.io/rb/sire)
5
+
6
+ Simple Immutable Relational Entity
7
+
8
+ ## Usage
9
+
10
+ Sire entities can be defined like Ruby Structs:
11
+
12
+ ``` ruby
13
+ require 'sire'
14
+
15
+ Foo = Sire.define(:name, :height)
16
+ ```
17
+
18
+ They are initialized with a hash, they have getters for each attribute and they include `enumerable`:
19
+
20
+ ``` ruby
21
+ foo_instance = Foo.new(name: 'Greg')
22
+ foo_instance.name # 'Greg'
23
+ foo_instance.each { |k, v| puts "My #{k} is #{v.inspect}" }
24
+ # $ "My name is Greg"
25
+ # $ "My height is nil"
26
+ ```
27
+
28
+ They can be used to define new entities that inherit their getters:
29
+
30
+ ``` ruby
31
+ Bar = Foo.define(:stick)
32
+ bar_instance = Bar.new(name: 'Harry', stick: 13)
33
+ ```
34
+
35
+ ### Relations
36
+
37
+ If an attribute matches the name of an Entity, it is treated as a relation and can be defined with nested hashes:
38
+
39
+ ``` ruby
40
+ Product = Sire.define(:name, :price)
41
+ LineItem = Sire.define(:product, :quantity)
42
+
43
+ line_item_instance = LineItem.new(product: {name: 'Cart', price: 1.30},
44
+ quantity: 2)
45
+ ```
46
+
47
+ If an attribute is the plural of the name of an Entity, it is treated as a has_many relation and can be defined with an array of nested hashes:
48
+
49
+ ``` ruby
50
+ Inventory = Sire.define(:products)
51
+
52
+ inventory_instance = Inventory.new(products: [{ name: 'bag', price: 0.66 },
53
+ { name: 'shoes', price: 1.30 }])
54
+ ```
55
+
56
+ ## Installation
57
+
58
+ Add this line to your application's Gemfile:
59
+
60
+ ```ruby
61
+ gem 'sire'
62
+ ```
63
+
64
+ ## Contributing
65
+
66
+ 1. Fork it ( https://github.com/[my-github-username]/sire/fork )
67
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
68
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
69
+ 4. Push to the branch (`git push origin my-new-feature`)
70
+ 5. Create a new Pull Request
@@ -0,0 +1,16 @@
1
+ require 'delegate'
2
+
3
+ module Sire
4
+ class Delegator < SimpleDelegator
5
+ def method_missing(*args, &b)
6
+ result = super
7
+ result.class == __getobj__.class ? create_new(result) : result
8
+ end
9
+
10
+ private
11
+
12
+ def create_new(result)
13
+ self.class.new(result)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ require 'sire/struct'
2
+ require 'descendants_tracker'
3
+
4
+ module Sire
5
+ class Entity < Struct
6
+ extend DescendantsTracker
7
+
8
+ def merge(other)
9
+ hash, other_hash = to_h, other.to_h
10
+
11
+ other_hash.each do |k, other_value|
12
+ value = hash[k]
13
+ hash[k] = value.is_a?(Array) ? value + other_value : other_value
14
+ end
15
+
16
+ self.class.new(hash)
17
+ end
18
+
19
+ private
20
+
21
+ def nestable_classes
22
+ Entity.descendants
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,63 @@
1
+ require 'sire/value_parser'
2
+
3
+ module Sire
4
+ class Struct
5
+ include Enumerable
6
+
7
+ class << self
8
+ attr_reader :attributes
9
+
10
+ def define(*attributes, &b)
11
+ Class.new(self) do
12
+ attr_accessor(*attributes)
13
+ private(*attributes.map { |a| "#{a}=" })
14
+ @attributes = [*attributes].freeze
15
+ class_eval(&b) if b
16
+ end
17
+ end
18
+
19
+ def [](hash = {})
20
+ new(hash)
21
+ end
22
+ end
23
+
24
+ def initialize(hash = {})
25
+ hash.each { |k, v| send("#{k}=", parser.parse_value(k, v)) }
26
+ freeze
27
+ end
28
+
29
+ def merge(other)
30
+ self.class.new(to_h.merge(other.to_h))
31
+ end
32
+
33
+ def attributes
34
+ self.class.attributes
35
+ end
36
+
37
+ def each
38
+ attributes.each { |a| yield a, send(a) }
39
+ end
40
+
41
+ def ==(other)
42
+ self.class == other.class && to_h == other.to_h
43
+ end
44
+
45
+ def to_s
46
+ "#{self.class}[#{map { |k, v| "#{k}: #{v.inspect}" }.join(', ') }]"
47
+ end
48
+
49
+ def inspect
50
+ to_s
51
+ end
52
+
53
+ private
54
+
55
+ def parser
56
+ @parser ||= ValueParser.new(nestable_classes)
57
+ end
58
+
59
+ def nestable_classes
60
+ []
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,57 @@
1
+ require 'inflecto'
2
+
3
+ module Sire
4
+ class ValueParser
5
+ def initialize(nestable_classes = [])
6
+ @nestable_classes = nestable_classes.reduce({}) do |h, c|
7
+ h.merge(demodulize_and_underscore(c) => c)
8
+ end
9
+ end
10
+
11
+ def parse_value(key, value)
12
+ @key, @value = key, value
13
+ return value.freeze if primitive?
14
+ return create_nested if single_nested_class
15
+ return create_many_nested if plural_nested_class
16
+ invalid
17
+ end
18
+
19
+ private
20
+
21
+ def primitive?
22
+ primitives.include?(@value.class)
23
+ end
24
+
25
+ def primitives
26
+ @@primitives ||= [String, Numeric, Rational, Complex, Integer, Fixnum, Float, Bignum,
27
+ TrueClass, FalseClass, Symbol, Date, Time, Regexp, NilClass]
28
+ end
29
+
30
+ def create_nested(nested_class = single_nested_class, arg = @value)
31
+ arg.is_a?(nested_class) ? arg : nested_class.new(arg).freeze
32
+ end
33
+
34
+ def create_many_nested
35
+ [*@value.map { |arg| create_nested(plural_nested_class, arg) }].freeze
36
+ end
37
+
38
+ def single_nested_class
39
+ @single_nested_class ||= @nestable_classes[@key.to_s]
40
+ end
41
+
42
+ def plural_nested_class
43
+ @plural_nested_class ||= @nestable_classes[Inflecto.singularize(@key.to_s)]
44
+ end
45
+
46
+ def invalid
47
+ message = "#{@key} is invalid. Accepted types: #{primitives | @nestable_classes.values}"
48
+ fail InvalidValueError, message
49
+ end
50
+
51
+ def demodulize_and_underscore(word)
52
+ Inflecto.underscore(Inflecto.demodulize(word))
53
+ end
54
+
55
+ InvalidValueError = Class.new(StandardError)
56
+ end
57
+ end
data/lib/sire.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'sire/entity'
2
+
3
+ module Sire
4
+ class << self
5
+ def define(*attributes, &b)
6
+ Entity.define(*attributes, &b)
7
+ end
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sire
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Max White
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: inflecto
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.0.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.0.2
33
+ - !ruby/object:Gem::Dependency
34
+ name: descendants_tracker
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.0'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 0.0.4
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '0.0'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 0.0.4
53
+ - !ruby/object:Gem::Dependency
54
+ name: rspec
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '3.1'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 3.1.0
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '3.1'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 3.1.0
73
+ description:
74
+ email: mushishi78@gmail.com
75
+ executables: []
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - LICENSE.txt
80
+ - README.md
81
+ - lib/sire.rb
82
+ - lib/sire/delegator.rb
83
+ - lib/sire/entity.rb
84
+ - lib/sire/struct.rb
85
+ - lib/sire/value_parser.rb
86
+ homepage:
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.2.2
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: Simple Immutable Relational Entity
110
+ test_files: []