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