yaml_b_sides 0.2.2 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf46816b3a78fe32bad41dc0fbcd5ee4d2642a01
4
- data.tar.gz: 24afd605cc2e41eef4a33a00db9c0fd3e3a34454
3
+ metadata.gz: 290831d7f1b375fdc3677f8482747c435028ac5f
4
+ data.tar.gz: 8ee7a67ada8164e8bbdbeb53fae5e49b9fc99f5c
5
5
  SHA512:
6
- metadata.gz: d8360db9e42b671111ab15622a2118aee1fd88f5b48dc6d68cbaab424546eacb17b8e290f0cf69916e2b7d1c44dcef8ef1798e62e778fd76f02878ed9511d52a
7
- data.tar.gz: 203d882c552eb01904ee6c2029d1e38d419dce056d23da6626bef28c656626cceb0ac0f371d7136168db09bf36cd0226c5963b714fdbcb3d8a7298d373917ae4
6
+ metadata.gz: a9e7b2bd03c35870aec5feb6ba9a42ffd79a139f05969a79b8a6f58d9454928261c139dec9a40289a1fe9e75c3855823b9ecc3d5f3046e37b1525d9d48992118
7
+ data.tar.gz: 9066c18974a19653f8adb232a53daea75ce2dcceb26a6c88b9eb3e14c67bd7871e6e7841555852277d8a16f8625104fb49c4c51cd3978f22addf9590c29c2a6e
data/README.md CHANGED
@@ -64,6 +64,18 @@ These are completely optional, but if you have a yaml file that's not uniform, a
64
64
  * `property( name, defaul= nil )` : will set a single field. will set defaul value to nil if omitted
65
65
  * `properties( props = {})` : takes a hash; will set many defaults at once
66
66
 
67
+ ### Associations
68
+
69
+ You can define simple associations that behave very much like ActiveRecord associations. Once you define your association, you will have a method with that name that will do the lookups and cache the results for you.
70
+
71
+ * `belongs_to association`: the base object has to have the association id
72
+ * will return a single object or nil
73
+ * `has_one`: the assiociation object has the id of the base.
74
+ * will return a single object or nil
75
+ * `has_many`: the association object has the id of the base.
76
+ * will return an array
77
+
78
+
67
79
  ### Example
68
80
 
69
81
  To use the `People` class from earlier, a fully fleshed out model would look something like:
@@ -74,11 +86,34 @@ class Person < YamlBSides::Base
74
86
  properties url_slug: "",
75
87
  bio: ""
76
88
 
89
+ has_many :nicknames
90
+
77
91
  index :name
78
92
  index :url_slug
79
93
  end
94
+
95
+ class Nickname < YamlBSides::Base
96
+ belongs_to :person
97
+ end
98
+
99
+ ```
100
+
101
+ and the YAML files will look like
102
+
103
+ ```yml
104
+ # in people.yml
105
+ mark_twain:
106
+ name: Mark Twain
107
+ url_slug: mark-twain
108
+ #...
109
+
110
+ # in nicknames.yml
111
+ sam_clemmens:
112
+ name: Samuel Clemmens
113
+ person_id: mark_twain
80
114
  ```
81
115
 
116
+
82
117
  ## Setup
83
118
 
84
119
  The setup is pretty straightforward. Yaml B-Sides wants a logger and a base dir to look for files in. An example config for a Rails app would look like:
data/lib/yaml_b_sides.rb CHANGED
@@ -8,6 +8,8 @@ require 'active_support/core_ext/hash'
8
8
  require 'yaml'
9
9
 
10
10
  module YamlBSides
11
+ autoload :Associatable, 'yaml_b_sides/associatable'
12
+ autoload :Associations, 'yaml_b_sides/associations'
11
13
  autoload :Base, 'yaml_b_sides/base'
12
14
  autoload :Cacheable, 'yaml_b_sides/cacheable'
13
15
  autoload :Instanceable, 'yaml_b_sides/instanceable'
@@ -0,0 +1,51 @@
1
+ module YamlBSides
2
+ module Associatable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class_attribute :__associations
7
+ self.__associations = {}
8
+
9
+ attr_accessor :_cached_associations
10
+
11
+ class << self
12
+
13
+ def belongs_to( name, opts = {} )
14
+ process Associations::BelongsTo.new( self, name, opts )
15
+ end
16
+
17
+ def has_one( name, opts = {} )
18
+ process Associations::HasOne.new( self, name, opts )
19
+ end
20
+
21
+ def has_many( name, opts = {} )
22
+ process Associations::HasMany.new( self, name, opts )
23
+ end
24
+
25
+ protected
26
+
27
+ def process( association )
28
+ associate association
29
+ methodize association
30
+ end
31
+
32
+ def associate( association )
33
+ self.__associations = __associations.merge association.name => association
34
+ end
35
+
36
+ def methodize( association )
37
+ define_method association.name do
38
+ self._cached_associations ||= {}
39
+
40
+ unless self._cached_associations.has_key? association.name
41
+ result = association.klass.send( association.action, association.query( self ) )
42
+
43
+ self._cached_associations[association.name] = result
44
+ end
45
+ self._cached_associations[association.name]
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,8 @@
1
+ module YamlBSides
2
+ module Associations
3
+ autoload :Base, 'yaml_b_sides/associations/base'
4
+ autoload :BelongsTo, 'yaml_b_sides/associations/belongs_to'
5
+ autoload :HasMany, 'yaml_b_sides/associations/has_many'
6
+ autoload :HasOne, 'yaml_b_sides/associations/has_one'
7
+ end
8
+ end
@@ -0,0 +1,33 @@
1
+ module YamlBSides
2
+ module Associations
3
+ class Base
4
+
5
+ attr_accessor :name, :opts, :key
6
+
7
+ def initialize( base_class, name, opts = {} )
8
+ self.name = name
9
+ self.opts = opts
10
+ self.key = "#{base_class.to_s.demodulize.underscore}_id"
11
+ end
12
+
13
+ def klass
14
+ @klass ||= association_class name, opts
15
+ end
16
+
17
+ protected
18
+
19
+ def association_class( name, opts = {} )
20
+ a_class = opts[:class] if opts.has_key? :class
21
+ a_class_name = opts[:class_name].constantize if opts.has_key? :class_name
22
+ derived_class = derived_class_for name
23
+
24
+ a_class || a_class_name || derived_class
25
+ end
26
+
27
+ def derived_class_for( name )
28
+ name.to_s.singularize.classify.constantize
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ module YamlBSides
2
+ module Associations
3
+ class BelongsTo < Base
4
+ def action
5
+ :find
6
+ end
7
+
8
+ def query( instance )
9
+ instance.send "#{name}_id"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module YamlBSides
2
+ module Associations
3
+ class HasMany < Base
4
+ def action
5
+ :where
6
+ end
7
+
8
+ def query( instance )
9
+ { key => instance.id }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module YamlBSides
2
+ module Associations
3
+ class HasOne < Base
4
+ def action
5
+ :find_by
6
+ end
7
+
8
+ def query( instance )
9
+ { key => instance.id }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,6 +1,7 @@
1
1
  module YamlBSides
2
2
  class Base
3
3
  include ActiveModel::Model
4
+ include Associatable
4
5
  include Cacheable
5
6
  include Propertiable
6
7
  include Indexable
@@ -15,7 +16,9 @@ module YamlBSides
15
16
  def load!
16
17
  @data = YAML.load_file( data_file ).with_indifferent_access
17
18
  idify_data!
18
- puts "#{self} successfully loaded data"
19
+ logger.info "#{self} successfully loaded data"
20
+ # let's preemptively index by id so that when we do a find_by id:, or a where id: it won't table scan
21
+ index :id
19
22
  rescue => e
20
23
  logger.error "#{self} failed to load data: #{e}"
21
24
  end
@@ -4,7 +4,7 @@ module YamlBSides
4
4
 
5
5
  included do
6
6
  class_attribute :__indices
7
- self.__indices = {}
7
+ self.__indices = { }
8
8
 
9
9
  class << self
10
10
  def index(field)
@@ -28,7 +28,6 @@ module YamlBSides
28
28
  def index_for(field)
29
29
  __indices[field]
30
30
  end
31
-
32
31
  end
33
32
  end
34
33
  end
@@ -11,13 +11,9 @@ module YamlBSides
11
11
  end
12
12
 
13
13
  def find_by(params = {})
14
- if all_indexed?(params.keys)
15
- results = find_by_indexed(params)
16
- else
17
- results = find_by_scan(params)
18
- end
14
+ results = where params
19
15
  raise "Could not find record that matches: #{params.inspect}" if results.empty?
20
- new results.first
16
+ results.first
21
17
  end
22
18
 
23
19
  def all
@@ -30,6 +26,18 @@ module YamlBSides
30
26
  new @data.values.first
31
27
  end
32
28
 
29
+ # TODO: move this into scopes
30
+ def where(params)
31
+ if all_indexed?(params.keys)
32
+ results = find_by_indexed(params)
33
+ else
34
+ results = find_by_scan(params)
35
+ end
36
+ results.map do |result|
37
+ new result
38
+ end
39
+ end
40
+
33
41
  private
34
42
 
35
43
  def find_by_scan(params)
@@ -1,3 +1,3 @@
1
1
  module YamlBSides
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yaml_b_sides
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Orlov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-09-13 00:00:00.000000000 Z
11
+ date: 2016-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -97,6 +97,12 @@ files:
97
97
  - bin/console
98
98
  - bin/setup
99
99
  - lib/yaml_b_sides.rb
100
+ - lib/yaml_b_sides/associatable.rb
101
+ - lib/yaml_b_sides/associations.rb
102
+ - lib/yaml_b_sides/associations/base.rb
103
+ - lib/yaml_b_sides/associations/belongs_to.rb
104
+ - lib/yaml_b_sides/associations/has_many.rb
105
+ - lib/yaml_b_sides/associations/has_one.rb
100
106
  - lib/yaml_b_sides/base.rb
101
107
  - lib/yaml_b_sides/cacheable.rb
102
108
  - lib/yaml_b_sides/index.rb