mother 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a67400fbd3434ab48672cbb60695a344d0ba8087
4
+ data.tar.gz: c5564367ecac57cc878175de55b3c5e6b66c5178
5
+ SHA512:
6
+ metadata.gz: ae5380c102c646f17fe497b00773c4a2900dc22a29f03bf44fccf76e63d6ede42060d01623ad705459f091cabc39e28ba5b240a2d7450c9fced2857ab791caf9
7
+ data.tar.gz: 7362f01bcb616d9b4f9ea2a58d384936a248ffb06cc3922b450680d39afdc743fda52f7abc5d5725766055161b43f77f0c39c608c03d6b336c203a679f689ba1
@@ -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
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.1
7
+ before_install: gem install bundler -v 1.16.4
@@ -0,0 +1,36 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ Please, let's be kind and considerate to each other. Don't harrass or
4
+ abuse anybody, regardless of age, body size, disability, ethnicity,
5
+ gender identity and expression, level of experience, nationality,
6
+ personal appearance, race, religion, or sexual identity and orientation.
7
+
8
+ ## Our Standards
9
+
10
+ Examples of behavior that contributes to creating a positive environment
11
+ include:
12
+
13
+ * Using welcoming and inclusive language
14
+ * Being respectful of differing viewpoints and experiences
15
+ * Gracefully accepting constructive criticism
16
+ * Focusing on what is best for the community
17
+ * Showing empathy towards other community members
18
+
19
+ Some examples of unacceptable behavior by participants would include:
20
+
21
+ * The use of sexualized language or imagery and unwelcome sexual attention or
22
+ advances
23
+ * Trolling, insulting/derogatory comments, and personal or political attacks
24
+ * Public or private harassment
25
+ * Publishing others' private information, such as a physical or electronic
26
+ address, without explicit permission
27
+ * Other conduct which could reasonably be considered inappropriate in a
28
+ professional setting
29
+
30
+ ## Attribution
31
+
32
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
33
+ available at [http://contributor-covenant.org/version/1/4][version]
34
+
35
+ [homepage]: http://contributor-covenant.org
36
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in mother.gemspec
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Joel Helbling
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.
@@ -0,0 +1,188 @@
1
+ # Mother
2
+
3
+ In the culinary world, "mother" is a natural complex of bacteria, proteins, enzymes and
4
+ fiber, which controls the fermentation of vinegar. It has this property, that the mother
5
+ derived in a new batch of vinegar can subsequently be used to start the fermentation of
6
+ yet another batch.
7
+
8
+ This gem proposes a similar arrangement, wherein a hash-like map or object comprises the
9
+ un-fermented source, while Mother (the ruby gem) provides a "fermented" abstraction which
10
+ 1) provides convenient access to the hash's properties, and
11
+ 2) generates a new Mother for any accessed property which is, itself, another hash, so
12
+ that hashes of hashes, once mothered, will yield children who are also mothers.
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'mother'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ $ bundle
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install mother
29
+
30
+ See? Not so bad.
31
+
32
+ ## Usage
33
+
34
+ Mother is easy to use. If you have a hash like so:
35
+
36
+ ```ruby
37
+ source = {
38
+ favorite_beverage: 'Chamomile Tea'
39
+ }
40
+ ```
41
+
42
+ Then create a Mother like so:
43
+
44
+ ```ruby
45
+ mom = Mother.create source
46
+ ```
47
+
48
+ And then you can call your mom (and you should!):
49
+
50
+ ```ruby
51
+ mom.favorite_beverage #=> 'Chamomile Tea'
52
+ ```
53
+
54
+ ### Mother from another resource
55
+
56
+ Mothers can create from hashes, but also from two popular hash-like file types, namely
57
+ YAML and JSON. These things will work (assuming the files actually exist):
58
+
59
+ ```ruby
60
+ mom = Mother.create 'math/theorems.yml'
61
+ mom = Mother.create './space_program.yaml'
62
+ mom = Mother.create '/opt/var/kids/birthdays.json'
63
+ ```
64
+
65
+ ### My what big hashes you have!
66
+
67
+ As mentioned earlier, Mothers can be grandmothers. Let's expand our earlier hash:
68
+
69
+ ```ruby
70
+ source = {
71
+ daughter: {
72
+ favorite_beverage: 'Gen Macha Tea'
73
+ }
74
+ }
75
+ ```
76
+
77
+ Then create a (grand)Mother just like we did before:
78
+
79
+ ```ruby
80
+ mom = Mother.create source
81
+ ```
82
+
83
+ And then we find that the daughter is also a Mother:
84
+
85
+ ```ruby
86
+ mom.daughter.class #=> Mother
87
+ ```
88
+
89
+ And indeed can be called in the same way:
90
+
91
+ ```ruby
92
+ mom.daughter.favorite_beverage #=> 'Gen Macha Tea'
93
+ ```
94
+
95
+ ### There was an old woman who lived in a shoe...
96
+
97
+ Mothers can also have whole broods of children (in Ruby these are called arrays),
98
+ any of which could be mothers:
99
+
100
+ ```ruby
101
+ source = {
102
+ brood: [
103
+ 12,
104
+ 'orange',
105
+ {
106
+ favorite_band: 'BTS'
107
+ }
108
+ ]
109
+ }
110
+ ```
111
+
112
+ We create the mother as usual:
113
+
114
+ ```ruby
115
+ mom = Mother.create source
116
+ ```
117
+
118
+ And then we find that we can access the array of children:
119
+
120
+ ```ruby
121
+ mom.brood.first #=> 12
122
+ mom.brood[1] #=> 'orange'
123
+ mom.brood.last.class #=> Mother
124
+ mom.brood.last.favorite_band #=> 'BTS'
125
+ ```
126
+
127
+ ### What About Demeter
128
+
129
+ At this point, I'd like to give a cheery halo to Demeter, the Greek mother goddess of
130
+ harvest, grain, and Persephone. You may be familiar with the programming principle to
131
+ which she has lent her name, namely the Law of Demeter, also known as the Principle of
132
+ Least Knowledge. According to this sage law, don't do this:
133
+
134
+ ```ruby
135
+ thing_1.thing_2.thing_that_thing_2_can_do(plenty, of: arguments)
136
+ ```
137
+
138
+ All those dots mean that our code, rather than just contenting itself with knowning how
139
+ to use thing_1, must also be inculcated with the proper use of thing_2. Bleh!
140
+
141
+ Law of Demeter violations are Bad ™, and you'll die if you use 'em. But in this
142
+ case, let's relax our customary parsimony and play around with them a bit!
143
+
144
+ I propose some guidelines:
145
+
146
+ - to keep things easy to reason about, consider not mutating your motherized hashes. Just
147
+ treat them like facts which don't change.
148
+ - avoid accessing them very deeply in any given context. Instead of calling the daughter
149
+ from the mother, and daisy-chaining calls to the daughter's attributes, instead hand
150
+ the daughter to another object, which can then access the daughter's attributes.
151
+ - don't worry so much.
152
+
153
+ The use case for which I dreamed this gem up was that I wanted to collect all my magical
154
+ values for a 2D game into a single YAML config file, and then be able to easily distribute
155
+ the subsections to various objects within the game, and to provide easy, method-like
156
+ access to all the properties (like they get to do with objects in JavaScript).
157
+
158
+ ## Development
159
+
160
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec`
161
+ to run the tests. You can also run `bin/console` for an interactive prompt that will allow
162
+ you to experiment.
163
+
164
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a
165
+ new version, update the version number in `version.rb`, and then run `bundle exec rake release`,
166
+ which will create a git tag for the version, push git commits and tags, and push the `.gem`
167
+ file to [rubygems.org](https://rubygems.org).
168
+
169
+ ## Contributing
170
+
171
+ Bug reports and pull requests are welcome on GitHub at https://github.com/joelhelbling/mother.
172
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are
173
+ expected to adhere to the [Contributor Covenant](https://www.contributor-covenant.org) code of
174
+ conduct.
175
+
176
+ ## License
177
+
178
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
179
+
180
+ ## Code of Conduct
181
+
182
+ Everyone interacting in Mother’s codebases, issue trackers, chat rooms and mailing lists shoulds
183
+ expect to follow the [code of conduct](https://github.com/joelhelbling/mother/blob/master/CODE_OF_CONDUCT.md).
184
+
185
+ ## Dedication
186
+
187
+ _I'd like to dedicate this gem to my Mom, who taught me to think analytically, who was my first
188
+ and best math teacher, and who encourages me to do my best, even nowadays. I love you, Mom._
@@ -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
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "mother"
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__)
@@ -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,58 @@
1
+ require 'mother/version'
2
+ require 'mother/collection'
3
+ require 'yaml'
4
+ require 'json'
5
+
6
+ class Mother
7
+ attr_reader :data
8
+
9
+ def initialize(argument)
10
+ self.class.argument_failure! unless argument.is_a?(Hash)
11
+
12
+ @data = argument
13
+ end
14
+
15
+ def [](key)
16
+ self.class.create ___fetch(key)
17
+ end
18
+
19
+ def keys
20
+ @data.keys
21
+ end
22
+
23
+ def method_missing(method, *args, &block)
24
+ self[method]
25
+ end
26
+
27
+ private
28
+
29
+ def ___fetch(key)
30
+ @data[key.to_sym] or @data[key.to_s]
31
+ end
32
+
33
+ class << self
34
+ def create(thing)
35
+ case thing
36
+ when Array
37
+ Collection.new self, thing
38
+ when Hash
39
+ new thing
40
+ when String
41
+ case
42
+ when thing.match(/\.ya?ml$/)
43
+ self.create YAML.load(File.read(thing))
44
+ when thing.match(/\.json$/)
45
+ self.create JSON.parse(File.read(thing))
46
+ else
47
+ thing
48
+ end
49
+ else
50
+ thing
51
+ end
52
+ end
53
+
54
+ def argument_failure!
55
+ raise ArgumentError.new('Must be a hash, or YAML/JSON filename')
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,30 @@
1
+ class Mother
2
+ class Collection
3
+ attr_reader :mother, :data
4
+
5
+ include Enumerable
6
+
7
+ def initialize(mother, argument)
8
+ mother.argument_failure! unless argument.is_a?(Array)
9
+
10
+ @mother = mother
11
+ @data = argument
12
+ end
13
+
14
+ def first
15
+ mother.create data.first
16
+ end
17
+
18
+ def last
19
+ mother.create data.last
20
+ end
21
+
22
+ def [](index)
23
+ mother.create data[index]
24
+ end
25
+
26
+ def each(&block)
27
+ data.map{ |i| mother.create i }.each(&block)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ class Mother
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,32 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "mother/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mother"
8
+ spec.version = Mother::VERSION
9
+ spec.authors = ["Joel Helbling"]
10
+ spec.email = ["joel@joelhelbling.com"]
11
+
12
+ spec.summary = %q{Method-ized access to a hash's children, and their children.}
13
+ spec.description = %q{Ever wish you had effortless, JS-like access to a deeply nested yaml?}
14
+ spec.homepage = "https://mother.joelhelbling.com"
15
+ spec.license = "MIT"
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.16"
27
+ spec.add_development_dependency "rake", "~> 12.3"
28
+ spec.add_development_dependency "rspec", "~> 3.8"
29
+ spec.add_development_dependency "rspec-given", "~> 3.8"
30
+ spec.add_development_dependency "fakefs", "0.18.0"
31
+ spec.add_development_dependency "pry"
32
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mother
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Joel Helbling
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-09-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '12.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '12.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.8'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-given
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: fakefs
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 0.18.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 0.18.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Ever wish you had effortless, JS-like access to a deeply nested yaml?
98
+ email:
99
+ - joel@joelhelbling.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".travis.yml"
107
+ - CODE_OF_CONDUCT.md
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/console
113
+ - bin/setup
114
+ - lib/mother.rb
115
+ - lib/mother/collection.rb
116
+ - lib/mother/version.rb
117
+ - mother.gemspec
118
+ homepage: https://mother.joelhelbling.com
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.6.14.1
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Method-ized access to a hash's children, and their children.
142
+ test_files: []