mother 0.1.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.
@@ -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: []