Op
10-3-2019 om 17:45 schreef Ben Coman:
Op
10-3-2019 om 16:19 schreef Ben
Coman:
I
could do
something like
this :
getImages
������ | json
numbers json2��
|
������ json :=
NeoJSONReader
������ ������
fromString:
������ ������ ������
(ZnEasy
������ ������ ������
������ get:
������ ������ ������
������ ������ '
https://www.rijksmuseum.nl/api/nl/collection?key=14OGzuak&format=json&type=schilderij&toppieces=True')
������ ������ ������
������ contents.
������ numbers :=
self class
fromJSON: json
������ numbers
do: [each |��
json :=��
.........
������������������������������������������������������������������������������������ imageData = self class ???
I'm not
sure what
"numbers"
refers to. It
seems a quite
non-domain
related
identifier.
and
collapsing
objects I see
the structure
is...
<snip>��
Did you work through this example I
provided?�� ��Please do so.
In a clean image...
Start
with only your
original code
(which was
good btw)...
�� ��
Paintings
class
>>��
fromJSON: json
�� ������ �� |
instance
artObjects |
�� ������
����instance :=
self new.
�� ������
����artObjects
:= json at:
#artObjects.
�� ������
����artObjects
�� �� �� ������
����do:
�� �� �� �� ��
������ ����[
:eachArtObject
| instance
addPainting:
(Painting
fromJSON:
eachArtObject)
].
�� ������ ����^
instance
except objectNumber(s) seem
associated with each painting, so should
be stored within the painting object, as
ADDED here...��
��Painting
class >>
fromJSON: json
�� ������ ����|
instance |
�� ������
����instance :=
self new.
�� ������
����instance
�� �� �� �� ��
��
objectNumber:��(json
at:
#objectNumber);��
��
��"<<<<<<<<ADDED"
�� �� �� ������
����title: (json
at: #title);
�� �� �� ������
����painter:
(json at:
#principalOrFirstMaker);
�� �� �� ������
����imageUrl:
((json at:
#webImage) at:
#url).
�� ������ ����^
instance
Evaluate
the following
in
Playground...��
�� ��
collectionJson
:=
NeoJSONReader
fromString:
(ZnEasy get:
collectionUrl)
contents.
�� ��
paintings :=
Paintings
fromJSON:��collectionJson.
�� ��
paintings
inspect.
then clean the DNU errors as they
occur (i.e. click the <Create>
button shown by the debugger, and fill
in as follows...)����
when you save the methods, choose
<Declare new instance variable>"����
�� �� Painting >> objectNumber:
aString��
objectNumber
:= aString����
�� ��
Painting
>>
title:
aString��
title
:= aString�� ��
��
�� ��
Painting
>>
painter:
aString��
painter
:= aString
�� ��
Painting
>>
imageUrl:
aString��
imageUrl
:= aString
�� ��
Paintings
>>
addPainting:
aPainting��
paintings
:= paintings
ifNil: [
OrderedCollection
new ].
paintings
add:
aPainting.
and an
inspector will
appear showing
a list of
paintings,
which��you can
drill down to
a painting and
see each has
the expected
data.
Now just
to round
things off...
�� ��
Painting
>> title
^
title
�� ��
Painting
>>
printOn:
aStream
super
printOn:
aStream.
aStream
<< ' ('
<< self
title <<
')'
to help
distinguish
each item in
the Inspector.
To extend
the Playground
code to
download and
display a
painting, in
Playground
evaluate...
�� ��
painting :=
paintings
first.
�� ��
imageResponse
:= ZnEasy get:
painting
imageUrl.
�� �� image
:=
ImageReadWriter
formFromStream: imageResponse entity readStream.
�� �� image
inspect.
�� ��
Paintings
>> first
^
paintings
first
�� ��
Painting
>>
imageUrl
^
imageUrl
and an
inspector on
the `image`
variable
displays the
painting on
the Morph tab.
Now to
mold the IDE
to your
domain...��
using
Spotter to
browser
gtInspector*
methods, a
promising find
is...
AbstractFileReference>>gitInspectorJpegIn:
from
which I
produced...
�� ��
Painting����>>��
gtInspectorJpegIn: composite
<gtInspectorPresentationOrder:
0>
composite
morph
title:
'Painting';
display:
[
ImageReadWriter
formFromStream: self imageEntity readStream ]��
Then
inspecting the
`paintings`
variable and
drilling down
to a painting��
pops up a
DNU
#imageEntity,
which can be
resolved by...
�� ��
Painting
>>
imageEntity
^
imageEntity
ifNil: [
imageEntity :=
(ZnEasy get:
self imageUrl)
entity ].
and you
get to see the
painting shown
in the
Inspector.
Now if I
understand
your
question...
"Do I need to
make some more
object to get
this
working..."
I'd
say... No. You
only want one
object for
each
painting.��Once
you have a
painting
object, it
should handle
all getting
all further
data it needs
for itself.
You don't
want duplicate
objects each
having half of
the data.
can
I for example
name the
function
fromJson2 or
fromJSONFromLink2��
?
By naming
convention
#fromJson:
implies it
sits on the
class side.
To get
further data
for an
existing
object��you
want an
instance-side
method, maybe
named
#getLink2Json.��
HTH,��
cheers
-ben
oke
numbers should be the objectNumbers
because for the rest I need them
��
I use a instance variable called
painting to hold the data.
so I can change the call to get data
for the painting to :
Painting class >> fromJSON: json
�� ������ ����| instance |
�� ������ ����instance := self new.
�� ������ ����instance
�� �� �� ������ �� objectNumber: ((json
at: #objectNumber).
�� ������ ����^ instance
so numbers should be a collection of
10 ObjectNumbers
I'm presuming that 10 objectNumbers
relate to 10 different paintings,
in which case, No, you should never
need to deal with a collection of 10
objectNumbers.
What you should have is a collection
of painting-objects which know their own
objectNumber
and then iterate that collection
sending each painting-object the message
"getLink2Json".
��
so I should use a loop to make a
call to the second api call
In Pharo OO��approach, you don't
"loop" on the "calls",��
you "iterate" on the "objects" asking
them to use their own data to do the
stuff they know how to do.
i.e. Let each object take care of
itself.
Which class is getImages defined on?��
That is really important to understand
your proposed solution.��
I'm just presuming its defined on the
class side of Paintings since your are
referring to the same URL as before.
btw, it won't work with two
identifiers "numbers painting" to the
left of the assignment symbol.�� Space
here bad.
��
������ numbers�� do: [each |�� json
:=�� call to the second url.here I
used each��
������������������������������������������������������������������������������������ imageData = self class
getLink2Json��
������������������������������������������������������������������������������������
json2 := call to the 3th url
�� �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� �� ��
�� �� ���� otherData := self class��
getLink3Json
�������������������������������������������������������������� �� ��
�� ��
no :)�� �� the "self class" seems
wrong.
getting extra data about a painting
should be handled by the instance side
of its painting-object.
��
Then�� I can�� I hope on every
json method fill in the data I need
Do I understand you well
I think not so well yet :)�� ��(or
else��I am missing something)
Keep trying.�� It will change the way
you think about programming.
Please work though the example I
provided.
cheers -ben
��
I did and it worked the same as my code
Still I do not see how to use then the objectNumber
in a second call to the api
for example
lets say we have only 1 objectNumber now
for example
SK-C-5
then I need that one here :
https://www.rijksmuseum.nl/api/nl/collection/SK-C-5?key=[API_KEY]&format=json
so I see a json response of this :
<snip>
where I at this moment need only artObjects -> makers -> name and artobject -> title
And I need to do that for all 10
But as far as I know I can only have one fromJson
You can have as many
Painting-class>>fromJsonXxxx methods as you
like,��
but you only call one of them once per painting.��
This has nothing to do with Json
and everything to do with your
Painting-class>>fromJson method creating a new
Painting-object,��
and you only want *one* Painting-object per
Json-painting, so you can only call one.
But actually, you don't need any
Painting>>fromJSON:.
Please delete it !!!!
Then modify the other one as follows...
�� �� Paintings class >> fromJSON: json
�� �� | instance |
�� �� instance := self new.
�� �� (json at: #artObjects)
�� �� �� �� do:
�� �� �� �� �� �� [ :artObjectJson
|��
�� �� |painting|
painting
:= Painting new.
�� �� painting
�� �� �� �� objectNumber:
(artObjectJson�� at: #objectNumber);
�� �� �� �� �� title:
(artObjectJson�� at: #title);
�� �� �� �� painter:
(artObjectJson�� at: #principalOrFirstMaker);
�� �� �� �� imageUrl:
((artObjectJson�� at: #webImage) at: #url).
instance
addPainting: painting ].
�� �� ^ instance
��
Does...
�� �� json := NeoJSONReader fromString: (ZnEasy
get: collectionUrl) contents.
�� �� paintings := Paintings fromJSON: json.
give you the same result as before?
so how do I take care that the second one is called and parsed
and the right info is on the Painting object
That is my question all the time
As I said before...
> What you should have is a collection of
painting-objects which know their own objectNumber
> and then iterate that collection sending
each painting-object the message "getLink2Json".
So more generically, add something like...
�� �� Painting >> getMoreData�� "or a better
name of your own"
���� �� �� �� �� ��| url json artObjectJson |��
Transcript crShow: 'Getting description from ', url.
json����:= (NeoJSONReader fromString: (ZnEasy get: url) contents).
artObjectJson := json at: 'artObject.
�� �� �� �� �� �� ��description := artObjectJson at:
'description'.
�� �� �� �� �� �� ��title :=��artObjectJson at: 'title'.
Now in playground, variable paintings holds a collection 10 ten paintings.
So lets ask each of them to get more data.
paintings do: [ :painting | painting getMoreData ].