Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Setup Ruby and install gems
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
ruby-version: 3.4.4
bundler-cache: true

- name: Run linters
Expand All @@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: [2.6, 2.7, 3.0]
ruby-version: [3.2, 3.3, 3.4.4]
steps:
- name: Checkout code
uses: actions/checkout@v2
Expand Down
6 changes: 1 addition & 5 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
AllCops:
TargetRubyVersion: 2.6
TargetRubyVersion: 3.0
NewCops: enable

Metrics/BlockLength:
Exclude:
- 'spec/**/*'

Style/OpenStructUse:
Exclude:
- 'spec/**/*'
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.2
3.4.4
125 changes: 117 additions & 8 deletions lib/microcms.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,99 @@ def client
end
end

# ResponseObject: replacement for OpenStruct
class ResponseObject
def initialize(hash = {})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about using Struct instead of hash

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Data, Struct

@data = hash.transform_keys(&:to_sym)
@data.each do |key, value|
@data[key] = convert_value(value)
end
end

def ==(other)
case other
when ResponseObject
@data == other.instance_variable_get(:@data)
when Hash
@data == other.transform_keys(&:to_sym)
else
false
end
end

def to_h
@data.transform_values do |value|
case value
when ResponseObject
value.to_h
when Array
value.map { |item| item.is_a?(ResponseObject) ? item.to_h : item }
else
value
end
end
end

def [](key)
@data[key.to_sym]
end

def []=(key, value)
@data[key.to_sym] = convert_value(value)
end

def method_missing(method_name, *args, &block)
method_str = method_name.to_s

if method_str.end_with?('=')
key = method_str.chomp('=').to_sym
@data[key] = convert_value(args.first)
elsif @data.key?(method_name)
@data[method_name]
else
super
end
end

def respond_to_missing?(method_name, include_private = false)
method_str = method_name.to_s
method_str.end_with?('=') || @data.key?(method_name) || super
end

def delete_field(key)
@data.delete(key.to_sym)
end

def keys
@data.keys
end

def values
@data.values
end

def each(&block)
@data.each(&block)
end

def inspect
"#<#{self.class.name} #{@data.inspect}>"
end

private

def convert_value(value)
case value
when Hash
ResponseObject.new(value)
when Array
value.map { |item| convert_value(item) }
else
value
end
end
end

# HttpUtil
module HttpUtil
def send_http_request(method, endpoint, path, query = nil, body = nil)
Expand All @@ -30,7 +123,7 @@ def send_http_request(method, endpoint, path, query = nil, body = nil)

raise APIError.new(status_code: res.code.to_i, body: res.body) if res.code.to_i >= 400

JSON.parse(res.body, object_class: OpenStruct) if res.header['Content-Type'].include?('application/json') # rubocop:disable Style/OpenStructUse
parse_json_response(res.body) if res.header['Content-Type'].include?('application/json')
end

private
Expand Down Expand Up @@ -60,7 +153,7 @@ def build_uri(endpoint, path, query)
origin = "https://#{@service_domain}.microcms.io"
path_with_id = path ? "/api/v1/#{endpoint}/#{path}" : "/api/v1/#{endpoint}"
encoded_query =
if !query || query.size.zero?
if !query || query.empty?
''
else
"?#{URI.encode_www_form(query)}"
Expand All @@ -75,6 +168,22 @@ def build_http(uri)

http
end

def parse_json_response(body)
parsed = JSON.parse(body)
convert_to_object(parsed)
end

def convert_to_object(obj)
case obj
when Hash
ResponseObject.new(obj)
when Array
obj.map { |item| convert_to_object(item) }
else
obj
end
end
end

# Client
Expand Down Expand Up @@ -102,7 +211,7 @@ def get(endpoint, id = '', option = {})
id,
{
draftKey: option[:draft_key],
fields: option[:fields] ? option[:fields].join(',') : nil,
fields: option[:fields]&.join(','),
depth: option[:depth]
}.select { |_key, value| value }
)
Expand All @@ -117,7 +226,7 @@ def create(endpoint, content, option = {})
end

def update(endpoint, content)
body = content.reject { |key, _value| key == :id }
body = content.except(:id)
send_http_request('PATCH', endpoint, content[:id], nil, body)
end

Expand All @@ -133,18 +242,18 @@ def build_query(option)
draftKey: option[:draftKey],
limit: option[:limit],
offset: option[:offset],
orders: option[:orders] ? option[:orders].join(',') : nil,
orders: option[:orders]&.join(','),
q: option[:q],
fields: option[:fields] ? option[:fields].join(',') : nil,
fields: option[:fields]&.join(','),
filters: option[:filters],
depth: option[:depth],
ids: option[:ids] ? option[:ids].join(',') : nil
ids: option[:ids]&.join(',')
}.select { |_key, value| value }
end
# rubocop:enable Style/MethodLength

def put(endpoint, content, option = {})
body = content.reject { |key, _value| key == :id }
body = content.except(:id)
send_http_request('PUT', endpoint, content[:id], option, body)
end

Expand Down
2 changes: 1 addition & 1 deletion microcms.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
spec.summary = 'microCMS Ruby SDK'
spec.description = 'microCMS Ruby SDK'
spec.homepage = 'https://github.com/microcmsio/microcms-ruby-sdk'
spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
spec.required_ruby_version = Gem::Requirement.new('>= 3.0')

spec.metadata['homepage_uri'] = spec.homepage
spec.metadata['source_code_uri'] = spec.homepage
Expand Down
16 changes: 8 additions & 8 deletions spec/microcms_spec.rb
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

microcms module dry

Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@

res = client.list('endpoint')

expect(res.contents).to eq [OpenStruct.new(content)]
expect(res.contents).to eq [MicroCMS::ResponseObject.new(content)]
end
end

Expand All @@ -87,7 +87,7 @@

res = client.get('endpoint', 'foo')

expect(res).to eq OpenStruct.new(content)
expect(res).to eq MicroCMS::ResponseObject.new(content)
end
end

Expand All @@ -104,7 +104,7 @@

res = client.create('endpoint', { text: 'Hello, new content!' })

expect(res).to eq OpenStruct.new({ id: 'bar' })
expect(res).to eq MicroCMS::ResponseObject.new({ id: 'bar' })
end
end

Expand All @@ -122,7 +122,7 @@

res = client.create('endpoint', { id: 'bar', text: 'Hello, new content!' })

expect(res).to eq OpenStruct.new({ id: 'bar' })
expect(res).to eq MicroCMS::ResponseObject.new({ id: 'bar' })
end
end

Expand All @@ -140,7 +140,7 @@

res = client.create('endpoint', { text: 'Hello, new content!' }, { status: 'draft' })

expect(res).to eq OpenStruct.new({ id: 'bar' })
expect(res).to eq MicroCMS::ResponseObject.new({ id: 'bar' })
end
end

Expand All @@ -158,7 +158,7 @@

res = client.update('endpoint', { id: 'bar', text: 'Hello, new content!' })

expect(res).to eq OpenStruct.new({ id: 'bar' })
expect(res).to eq MicroCMS::ResponseObject.new({ id: 'bar' })
end
end

Expand All @@ -180,7 +180,7 @@
it 'raises MicroCMS::APIError' do
expect_any_instance_of(Net::HTTP).to receive(:request).and_return(mock_client_error_response)
expect { client.create('endpoint', { id: 'bar', baz: 'quux' }) }.to(
raise_error(an_instance_of(::MicroCMS::APIError)
raise_error(an_instance_of(MicroCMS::APIError)
.and(have_attributes({
status_code: 400,
message: 'client error',
Expand All @@ -195,7 +195,7 @@
expect_any_instance_of(Net::HTTP).to receive(:request).and_return(mock_server_error_response)

expect { client.create('endpoint', { id: 'bar', baz: 'quux' }) }.to(
raise_error(an_instance_of(::MicroCMS::APIError)
raise_error(an_instance_of(MicroCMS::APIError)
.and(have_attributes({
status_code: 500,
message: 'server error',
Expand Down
42 changes: 42 additions & 0 deletions test_response_object.rb
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI gen

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

# Simple test to verify ResponseObject functionality
require_relative 'lib/microcms'

# Test ResponseObject creation and access
puts 'Testing ResponseObject...'

# Test 1: Basic creation and access
response = MicroCMS::ResponseObject.new({ id: 'test123', name: 'Test Article' })
puts "✓ Basic creation: #{response.id} - #{response.name}"

# Test 2: Nested objects
nested_data = {
id: 'article1',
title: 'Hello World',
author: {
id: 'author1',
name: 'John Doe'
},
tags: %w[ruby programming]
}

nested_response = MicroCMS::ResponseObject.new(nested_data)
puts "✓ Nested access: #{nested_response.author.name}"
puts "✓ Array access: #{nested_response.tags}"

# Test 3: Equality comparison
response1 = MicroCMS::ResponseObject.new({ id: 'test' })
response2 = MicroCMS::ResponseObject.new({ id: 'test' })
puts "✓ Equality test: #{response1 == response2}"

# Test 4: Hash conversion
hash_result = nested_response.to_h
puts "✓ Hash conversion: #{hash_result[:author][:name]}"

# Test 5: delete_field functionality
response.delete_field(:name)
puts "✓ Delete field test: name should be nil: #{response.name.nil?}"

puts "\nAll ResponseObject tests passed! ✅"