Skip to content

Commit

Permalink
Add option to configure gem (#3)
Browse files Browse the repository at this point in the history
* Add config

Add specs for config

Bump version to 0.3.0

Update README.md

Update README.md

Run rubocop

Fix typo

* Change config approach to module builder

* Fix default args
  • Loading branch information
m3xq authored Oct 25, 2021
1 parent 8ee2485 commit 688a808
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 20 deletions.
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
ez_attributes (0.2.2)
ez_attributes (0.3.0)

GEM
remote: https://rubygems.org/
Expand Down Expand Up @@ -93,4 +93,4 @@ DEPENDENCIES
yard

BUNDLED WITH
2.2.25
2.2.29
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ user.name
# => "Matz"
```

### Configuration
You can disable getters
```ruby
class User
extend EzAttributes.configure(getters: false)

attributes :name, :age, email: 'guest@user.com'
end

u = User.new(name: 'Matz', age: 22)
# => #<User:0x000055bac152f130 @name="Matz", @age=22, @email="guest@user.com">

u.name
# NoMethodError (undefined method `name' for #<User:0x000055bac152f130>)

```

## Development

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.
Expand Down
48 changes: 30 additions & 18 deletions lib/ez_attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,44 @@
# => #<User:0x000055bac152f130 @name="Matheus", @age=22, @email="guest@user.com">
module EzAttributes
# Gem version
VERSION = "0.2.2"
VERSION = "0.3.0"

# Attributes that won't have a getter to prevent conflicts with default methods
EXCEPTIONS = [:class].freeze

# Defines multiple keyword arguments for a class initializer
def attributes(*args, **args_with_default)
required_args = args.map { |name| "#{name}:" }
optional_args = args_with_default.map { |name, _| "#{name}: __args_with_default[:#{name}]" }
init_args = (required_args + optional_args).join(", ")
def self.extended(other)
other.extend configure
end

def self.configure(getters: true)
mod = Module.new

mod.module_eval do
# Defines multiple keyword arguments for a class initializer
define_method :attributes do |*args, **args_with_default|
required_args = args.map { |name| "#{name}:" }
optional_args = args_with_default.map { |name, _| "#{name}: __args_with_default[:#{name}]" }
init_args = (required_args + optional_args).join(", ")

define_method("__args_with_default", -> { Marshal.load(Marshal.dump(args_with_default)) })
private :__args_with_default
define_method("__args_with_default", -> { Marshal.load(Marshal.dump(args_with_default)) })
private :__args_with_default

all_args = args + args_with_default.keys
attr_reader(*(all_args - EXCEPTIONS))
all_args = args + args_with_default.keys
attr_reader(*(all_args - EXCEPTIONS)) if getters

class_eval <<~RUBY, __FILE__, __LINE__ + 1
def initialize(#{init_args})
#{all_args.map { |name| "@#{name} = binding.local_variable_get(:#{name})" }.join("; ")}
class_eval <<~RUBY, __FILE__, __LINE__ + 1
def initialize(#{init_args})
#{all_args.map { |name| "@#{name} = binding.local_variable_get(:#{name})" }.join("; ")}
end
RUBY
end
RUBY
end

# Defines a single keyword argument for a class initializer
def attribute(name)
attributes(name)
# Defines a single keyword argument for a class initializer
define_method :attribute do |name|
attributes(name)
end
end

mod
end
end
42 changes: 42 additions & 0 deletions spec/ez_attributes_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,46 @@ def change_attr
expect(obj2.a).to eq [1]
end
end

context "when config is not present" do
let(:test_class) do
Class.new do
extend EzAttributes

attributes :test
end
end

it "defines getters" do
expect { test_class.new(test: "test").test }.not_to raise_error
end
end

context "when config is present and has getters: true" do
let(:test_class) do
Class.new do
extend EzAttributes.configure(getters: true)

attributes :test
end
end

it "defines getters" do
expect { test_class.new(test: "test").test }.not_to raise_error
end
end

context "when config is present and has getters: false" do
let(:test_class) do
Class.new do
extend EzAttributes.configure(getters: false)

attributes :test
end
end

it "does not define getters" do
expect { test_class.new(test: "test").test }.to raise_error NoMethodError
end
end
end

0 comments on commit 688a808

Please sign in to comment.