yml_record 0.0.1 → 0.1.4

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
  SHA256:
3
- metadata.gz: '005397e7310eb09049d530abdaf0adb2f29c5a939c438bfd33d225cd40cd26df'
4
- data.tar.gz: bca02908ba64cd0e2a61b1d7f375e9cce1e7e68b798064b91bcbc63f9ebf5726
3
+ metadata.gz: bc3ea52217e192ab11305116a1c9c4822209a106c8412cb59f4e17e399da6698
4
+ data.tar.gz: 7beec8530b22a8a6545c07dc4f443d536d95f8b0f0a85a92fd9c75ea9ee8af24
5
5
  SHA512:
6
- metadata.gz: 762b13835669bc08e09249648cb89259f24477fc4250a0c3adac452f70db0ade5ff6f023b3b1775e22935590676789801dbb85f25365bbc1c28fb9a1c42237ac
7
- data.tar.gz: 9147868feeb335e7ac18ba44e6422a7a46fed2f239beeee57f01d6fc3df9603304ed5466a8269972d7f7c9c4a9e5ae15b31123e5100b45c732f4ef1533eff0c4
6
+ metadata.gz: 18e31398c0bccae297cc956c07b2bf9494beab4054f0f423eda53d1c729725407bbde37c0bdfc61342e4fbc565a6b732fac9461499460815449d3014bda5b750
7
+ data.tar.gz: 14af825e0bec0db3e3923b300adf7467acad081c2a6fce55bc2d10a6cb5c7e42fb683d227eadf49d8bcc6edef7a68173821cae10a5bbe7c201ee446166537bd7
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.0
6
+ before_install: gem install bundler -v 2.1.4
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at tom@sherpa.net.au. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in yml_record.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "rspec", "~> 3.0"
8
+ gem "activesupport", '~> 5.0'
data/Gemfile.lock ADDED
@@ -0,0 +1,47 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ yml_record (0.1.3)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activesupport (5.2.8)
10
+ concurrent-ruby (~> 1.0, >= 1.0.2)
11
+ i18n (>= 0.7, < 2)
12
+ minitest (~> 5.1)
13
+ tzinfo (~> 1.1)
14
+ concurrent-ruby (1.1.10)
15
+ diff-lcs (1.4.4)
16
+ i18n (1.10.0)
17
+ concurrent-ruby (~> 1.0)
18
+ minitest (5.15.0)
19
+ rake (12.3.3)
20
+ rspec (3.10.0)
21
+ rspec-core (~> 3.10.0)
22
+ rspec-expectations (~> 3.10.0)
23
+ rspec-mocks (~> 3.10.0)
24
+ rspec-core (3.10.1)
25
+ rspec-support (~> 3.10.0)
26
+ rspec-expectations (3.10.1)
27
+ diff-lcs (>= 1.2.0, < 2.0)
28
+ rspec-support (~> 3.10.0)
29
+ rspec-mocks (3.10.2)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.10.0)
32
+ rspec-support (3.10.2)
33
+ thread_safe (0.3.6)
34
+ tzinfo (1.2.9)
35
+ thread_safe (~> 0.1)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ activesupport (~> 5.0)
42
+ rake (~> 12.0)
43
+ rspec (~> 3.0)
44
+ yml_record!
45
+
46
+ BUNDLED WITH
47
+ 2.1.4
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Tom Barker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,181 @@
1
+ # YmlRecord
2
+
3
+ YmlRecord is a gem to allow easy instantiating of classes from a yml file and exposing an ActiveRecord-esque api.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'yml_record'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install yml_record
20
+
21
+ ## Usage
22
+
23
+ Create an ApplicationYmlRecord model that inherits from YmlRecord::Base
24
+ ```
25
+ # app/models/application_yml_record.rb
26
+ class ApplicationYmlRecord < YmlRecord::Base; end
27
+ ```
28
+
29
+ Create a model that will be backed by a yml data file and inherit from ApplicationYmlRecord.
30
+ ```
31
+ # app/models/example_model.rb
32
+ class ExampleModel < ApplicationYmlRecord
33
+ ```
34
+
35
+ Add a yml file (named the same as your model) to the `config/data/` folder
36
+ ```
37
+ # config/data/example_model.yml
38
+ - id: 1
39
+ name: one
40
+ - id: 2
41
+ name: two
42
+ ```
43
+
44
+ This model can now be used as if it were backed by activerecord and a database table.
45
+ N.B: this functionality does not include create or update actions.
46
+
47
+ ```
48
+ ExampleModel.all #=> relation of 2 instances
49
+ ExampleModel.where(name: 'one') #=> relation of 1 (first) instance
50
+ ExampleModel.find(1) #=> first instance of ExampleModel
51
+ etc
52
+ ```
53
+
54
+ The automatic folder location for the yml files is `config/data/` but this can be manually overwritten
55
+ The automatic file name for each model is the demodulized snakecase class name (e.g `App::ExampleClass` => `example_class.yml`)
56
+
57
+ This automatic functionality can be overwritten when needed
58
+ ```
59
+ # to overwrite individual class's data filename to `bar.yml`
60
+ class Foo < ApplicationYmlRecord
61
+ self.filename = 'bar'
62
+ end
63
+
64
+ # to overwrite data folder location
65
+ class ApplicationYmlRecord < YamlRecord::Base
66
+ self.filepath = 'another/folder'
67
+ end
68
+ ```
69
+ will look for data in `another/folder/bar/yml`
70
+
71
+ See below for specific functionality implementations.
72
+ The implementation examples assume the following setup
73
+ ```
74
+ # example.yaml
75
+ - id: 1
76
+ old: true
77
+ colour: :green
78
+ - id: 2
79
+ colour: :red
80
+ old: true
81
+ - id: 3
82
+ colour: :red
83
+ old: false
84
+
85
+ class Example < YamlRecord::Base
86
+ end
87
+ ```
88
+
89
+ ### Class methods
90
+ #### Scopes
91
+ Scopes will return a chainable relation with instances that match the attributes similar to active record relations
92
+ ```
93
+ Example.where(old: true).where(colour: :red) #=> [<Example id: 1 />]
94
+ is the same as
95
+ Example.where(old: true, colour: :red)
96
+ ```
97
+
98
+ ### Relating to YamlRecord classes
99
+ Other classes can relate to yaml record classes using an active record style integration
100
+ #### Has Many
101
+ When storing primary keys of yaml records on another class, the belongs_to method can be used to create a parent like relationship.
102
+ If the other class is dynamic (e.g: backed by a database) then the relationship can be set to dynamic (default).
103
+ Otherwise (e.g: that class is also a yaml record) the relationship can be set to being not dynamic.
104
+ ```
105
+ class Child
106
+ attr_accessor :example_id
107
+
108
+ YmlRecord.relationships.belongs_to self, :example
109
+ end
110
+ ```
111
+ This will add `Child#example` and `Child.example=(other_example)` instance methods.
112
+
113
+ The following will mark this relationship as static (not dynamic), which will not create the setter method (`Child.example=(other_example)`)
114
+ ```
115
+ YmlRecord.relationships.belongs_to self, :example, dynamic: false
116
+ ```
117
+
118
+ The following keys can all be manually set in the same way as with active record belongs to:
119
+ - foreign_key
120
+ - primary_key
121
+ - class_name
122
+
123
+ If using active record to relate to yaml records, the following can be added to the application record to streamline implementation
124
+
125
+ ```
126
+ class Car < ApplicationYmlRecord; end
127
+
128
+ class ApplicationRecord < ActiveRecord::Base
129
+ def self.belongs_to(name, scope = nil, yml_relationship: false, **opts, &block)
130
+ return super(name, scope, **opts, &block)
131
+
132
+ YmlRecord.relationships.belongs_to self, name, scope, **opts, &block
133
+ end
134
+ end
135
+
136
+ # has db column of car_id (of type corresponding to car primary key)
137
+ class Driver < ApplicationRecord
138
+ belongs_to :car, yml_relationship: true
139
+ end
140
+ ```
141
+
142
+ ### Instance methods
143
+ #### Boolean methods
144
+
145
+ When an attribute is a boolean a boolean instance method is automatically created.
146
+ ```
147
+ Example.find(1).old? #=> true
148
+ Example.find(2).old? #=> false
149
+ ```
150
+
151
+ ### TODO documentation
152
+ TODO: document implementation of custom filename
153
+ TODO: document implementation of custom identifier
154
+ TODO: document implementation of scope
155
+ TODO: document implementation of enum
156
+
157
+ ## Future implementations
158
+ TODO: document
159
+
160
+ - [ ] setting data folder in initializer for gem
161
+ - [ ] allow setting of specific data for specific deployments
162
+
163
+
164
+ ## Development
165
+
166
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
167
+
168
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
169
+
170
+ ## Contributing
171
+
172
+ Bug reports and pull requests are welcome on GitHub at https://github.com/tjbarker/yml_record. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/tjbarker/yml_record/blob/master/CODE_OF_CONDUCT.md).
173
+
174
+
175
+ ## License
176
+
177
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
178
+
179
+ ## Code of Conduct
180
+
181
+ Everyone interacting in the YmlRecord project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/tjbarker/yml_record/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "yml_record"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,24 @@
1
+ require 'yml_record/helpers/delegate_missing_to.rb'
2
+ require 'ostruct'
3
+
4
+ module YmlRecord
5
+ # class to hold attributes, just hold and return for now
6
+ class Attributes
7
+ extend DelegateMissingTo
8
+ delegate_missing_to :store
9
+
10
+ def initialize(**opts)
11
+ new_opts = opts.each_with_object({}) do |(key, value), acc|
12
+ if [true, false].include?(value) && !key.to_s.end_with?('?')
13
+ acc["#{key}?"] = value
14
+ end
15
+ acc[key] = value
16
+ end
17
+ @store = OpenStruct.new(**new_opts)
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :store
23
+ end
24
+ end
@@ -0,0 +1,53 @@
1
+ require 'yaml'
2
+ require 'yml_record/helpers/delegate_missing_to.rb'
3
+ require 'yml_record/relation.rb'
4
+ require 'yml_record/attributes.rb'
5
+ require 'yml_record/builders/enum.rb'
6
+ require 'yml_record/builders/scope.rb'
7
+ require 'yml_record/builders/data_loader.rb'
8
+ require 'yml_record/builders/all.rb'
9
+ require 'yml_record/builders/has_attributes.rb'
10
+
11
+ module YmlRecord
12
+ class Base
13
+ extend DelegateMissingTo
14
+
15
+ include Builders::HasAttributes
16
+
17
+ class << self
18
+ extend DelegateMissingTo
19
+
20
+ include Builders::DataLoader
21
+ include Builders::All # Includes a delegate_missing_to_all
22
+ include Builders::Enum
23
+ include Builders::Scope
24
+
25
+ def primary_key
26
+ @primary_key ||= 'id'
27
+ end
28
+
29
+ protected
30
+
31
+ def boolean_columns(*keys)
32
+ raise NotImplementedError, 'this method is no longer necessary, data with a boolean value automatically generates a `?` getter'
33
+ end
34
+
35
+ private
36
+
37
+ attr_writer :primary_key
38
+
39
+ def relation_klass
40
+ @relation_klass ||= const_set('Relation', Class.new(Relation))
41
+ end
42
+ end
43
+
44
+ def ==(other)
45
+ other.send(:__identifier) == __identifier
46
+ end
47
+
48
+ # for inheritor to overwrite if other means of equating is necessary
49
+ def __identifier
50
+ respond_to?(:id) ? "id-#{id}" : "hash-#{hash}"
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,15 @@
1
+ require 'yml_record/helpers/delegate_missing_to.rb'
2
+
3
+ module YmlRecord
4
+ module Builders
5
+ module All
6
+ extend DelegateMissingTo
7
+
8
+ def all
9
+ @all ||= relation_klass.new(data.map { |op| new(**op) })
10
+ end
11
+
12
+ delegate_missing_to :all
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ module YmlRecord
2
+ module Builders
3
+ module DataLoader
4
+ protected
5
+
6
+ def data
7
+ @data ||= YAML.load_file(filepath)
8
+ end
9
+
10
+ private
11
+
12
+ attr_writer :filename, :filepath, :primary_key
13
+
14
+ def filename
15
+ @filename ||= name.demodulize.snakecase
16
+ end
17
+
18
+ def filepath
19
+ @filepath ||= 'config/data'
20
+ end
21
+
22
+ def filelocation
23
+ @filelocation ||= "#{filepath}/#{filename}.yml"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,40 @@
1
+ module YmlRecord
2
+ module Pluralize
3
+ #TODO: implement this properly
4
+ def self.call(string)
5
+ "#{string}s"
6
+ end
7
+ end
8
+
9
+ module Builders
10
+ module Enum
11
+
12
+ # will define:
13
+ # - the list of keys on class
14
+ # - for each enum value a check method, e.g: Class.new.key? => Boolean
15
+ # - for each enum value a class scope, e.g: Class.key => relation
16
+ # singular true => Class.key will return first instance with value
17
+ # singular false => Class.key will return a relation of instances with value
18
+ def enum(key, singular: false)
19
+ key = key.to_s
20
+ plural = Pluralize.call(key)
21
+
22
+ define_singleton_method plural do
23
+ all.inject([]) do |acc, d|
24
+ acc << d.send(key)
25
+ end.uniq.compact
26
+ end
27
+
28
+ send(plural).each do |value|
29
+ define_method "#{value}?" do
30
+ send(key) == value
31
+ end
32
+
33
+ define_singleton_method value do
34
+ send(singular ? :find_by : :where, key => value)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,19 @@
1
+ require 'yml_record/helpers/delegate_missing_to.rb'
2
+
3
+ module YmlRecord
4
+ module Builders
5
+ module HasAttributes
6
+ extend DelegateMissingTo
7
+
8
+ def initialize(**data)
9
+ @attributes = Attributes.new(**data)
10
+ end
11
+
12
+ delegate_missing_to :attributes
13
+
14
+ private
15
+
16
+ attr_reader :attributes
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ module YmlRecord
2
+ module Builders
3
+ module Scope
4
+ def scope(name, body, &_block)
5
+ body.respond_to?(:call) || raise(ArgumentError, 'The scope body needs to be callable.')
6
+ block_given? && raise(NotImplementedError, 'Scopes do not handle extension.')
7
+
8
+ relation_klass.define_method name do
9
+ instance_exec(&body)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ module DelegateMissingTo
2
+ def delegate_missing_to(relation)
3
+ define_method :respond_to_missing? do |name, include_private = false|
4
+ send(relation).respond_to?(name) || super(name, include_private)
5
+ end
6
+
7
+ define_method :method_missing do |method, *args, **opts, &block|
8
+ if send(relation).respond_to?(method)
9
+ send(relation).public_send(method, *args, **opts, &block)
10
+ else
11
+ begin
12
+ super(method, *args, **opts, &block)
13
+ rescue NoMethodError
14
+ raise
15
+ end
16
+ end
17
+ end
18
+
19
+ private :respond_to_missing?
20
+ private :method_missing
21
+ end
22
+ end
@@ -0,0 +1,46 @@
1
+ require 'yml_record/helpers/delegate_missing_to.rb'
2
+
3
+ module YmlRecord
4
+ class Relation
5
+ extend DelegateMissingTo
6
+ delegate_missing_to :list
7
+
8
+ def initialize(list)
9
+ @list = list
10
+ end
11
+
12
+ def where(**opts)
13
+ self.class.new(opts.inject(list) do |list, (key, values)|
14
+ list.select do |inst|
15
+ value_list = values.nil? ? [nil] : Array(values)
16
+ value_list.include?(inst.send(key))
17
+ end
18
+ end)
19
+ end
20
+
21
+ def find_by(**opts)
22
+ where(**opts).first
23
+ end
24
+
25
+ def order(*keys, **keys_with_direction)
26
+ direction_list = keys.inject(keys_with_direction) do |acc, key|
27
+ { key => :asc }.merge(**acc)
28
+ end
29
+
30
+ self.class.new(list.sort_by do |inst|
31
+ direction_list.map do |key, direction|
32
+ direction == :asc ? inst.send(key) : -inst.send(key)
33
+ end
34
+ end)
35
+ end
36
+
37
+ def all
38
+ self
39
+ end
40
+
41
+ private
42
+
43
+ attr_reader :list
44
+ end
45
+ end
46
+
@@ -0,0 +1,39 @@
1
+ require 'active_support/core_ext/string'
2
+
3
+ module YmlRecord
4
+ module RelationshipBuilders
5
+ class BelongsTo
6
+ def self.build(model, name, scope = nil, **options, &_block)
7
+ new(model, name, scope, **options).build
8
+ end
9
+
10
+ def initialize(model, name, scope, dynamic: true, **options)
11
+ @model = model
12
+ @name = name
13
+ raise(NotImplementedError, 'yml record belongs to with scope is not yet implemented') if !!scope
14
+ @dynamic = dynamic
15
+ @options = options
16
+ end
17
+
18
+ def build
19
+ klass = (options.fetch(:class_name, nil) || name.to_s.camelize).constantize
20
+ klass_primary_key = options.fetch(:primay_key, klass.primary_key)
21
+ foreign_key = options.fetch(:foreign_key, "#{name}_#{klass_primary_key}")
22
+
23
+ model.define_method name do
24
+ klass.find_by(klass_primary_key => send(foreign_key))
25
+ end
26
+
27
+ if dynamic
28
+ model.define_method "#{name}=" do |instance|
29
+ self.send("#{foreign_key}=", instance.send(klass_primary_key))
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :model, :name, :dynamic, :options
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ require 'yml_record/relationship_builders/belongs_to.rb'
2
+
3
+ module YmlRecord
4
+ module RelationshipBuilders
5
+ def self.belongs_to(*args, **opts, &block)
6
+ BelongsTo.build(*args, **opts, &block)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module YmlRecord
2
+ VERSION = "0.1.4"
3
+ end
data/lib/yml_record.rb CHANGED
@@ -1,5 +1,11 @@
1
- class YmlRecord
2
- def self.testing_method
3
- 'This is a test'
1
+ require 'yml_record/base'
2
+ require "yml_record/version"
3
+ require 'yml_record/relationship_builders'
4
+
5
+ module YmlRecord
6
+ class Error < StandardError; end
7
+
8
+ def self.relationships
9
+ YmlRecord::RelationshipBuilders
4
10
  end
5
11
  end
@@ -0,0 +1,30 @@
1
+ require_relative 'lib/yml_record/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "yml_record"
5
+ spec.version = YmlRecord::VERSION
6
+ spec.authors = ["Tom Barker"]
7
+ spec.email = ["thomasjohnbarker@gmail.com"]
8
+
9
+ spec.summary = %q{A gem for presenting ActiveRecord like interface for yml backed models}
10
+ spec.description = %q{A gem for presenting ActiveRecord like interface for yml backed models}
11
+ spec.homepage = "https://rubygems.org/gems/yml_record"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+ spec.metadata["source_code_uri"] = "https://github.com/tjbarker/yml_record#readme"
15
+
16
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
17
+
18
+ # spec.metadata["homepage_uri"] = spec.homepage
19
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+ end
metadata CHANGED
@@ -1,26 +1,52 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yml_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
- - Thomas Barker
7
+ - Tom Barker
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-10 00:00:00.000000000 Z
11
+ date: 2022-07-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A gem for presenting ActiveRecord like interface for yml backed models
14
- email: thomasjohnbarker@gmail.com
14
+ email:
15
+ - thomasjohnbarker@gmail.com
15
16
  executables: []
16
17
  extensions: []
17
18
  extra_rdoc_files: []
18
19
  files:
20
+ - ".gitignore"
21
+ - ".rspec"
22
+ - ".travis.yml"
23
+ - CODE_OF_CONDUCT.md
24
+ - Gemfile
25
+ - Gemfile.lock
26
+ - LICENSE.txt
27
+ - README.md
28
+ - Rakefile
29
+ - bin/console
30
+ - bin/setup
19
31
  - lib/yml_record.rb
32
+ - lib/yml_record/attributes.rb
33
+ - lib/yml_record/base.rb
34
+ - lib/yml_record/builders/all.rb
35
+ - lib/yml_record/builders/data_loader.rb
36
+ - lib/yml_record/builders/enum.rb
37
+ - lib/yml_record/builders/has_attributes.rb
38
+ - lib/yml_record/builders/scope.rb
39
+ - lib/yml_record/helpers/delegate_missing_to.rb
40
+ - lib/yml_record/relation.rb
41
+ - lib/yml_record/relationship_builders.rb
42
+ - lib/yml_record/relationship_builders/belongs_to.rb
43
+ - lib/yml_record/version.rb
44
+ - yml_record.gemspec
20
45
  homepage: https://rubygems.org/gems/yml_record
21
46
  licenses:
22
47
  - MIT
23
- metadata: {}
48
+ metadata:
49
+ source_code_uri: https://github.com/tjbarker/yml_record#readme
24
50
  post_install_message:
25
51
  rdoc_options: []
26
52
  require_paths:
@@ -29,7 +55,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
29
55
  requirements:
30
56
  - - ">="
31
57
  - !ruby/object:Gem::Version
32
- version: '0'
58
+ version: 2.3.0
33
59
  required_rubygems_version: !ruby/object:Gem::Requirement
34
60
  requirements:
35
61
  - - ">="